Java For-loop изменяет числовой результат при изменении типа переменной цикла
Я написал программу для вычисления номера PI с помощью формулы Лейбница:
[![Leibniz formula]]()
Я написал for-loop с типом инициализации "int", цикл работает отлично, но когда я изменил тип инициализации на "long", результат изменился. Это происходит только тогда, когда цикл превышает миллиард. Это делает "int-loop" вычисляет PI более точным, чем "длинный цикл". Я не знаю, почему это происходит. Пожалуйста, помогите мне понять эту проблему. Благодарю! и вот мой код.
public static void main(String[] args) {
double result1 = 0;
double result2 = 0;
double sign = 1;
for (int i = 0; i <= 1607702095; i++) {
result1 += sign/(2 * i + 1);
sign *= -1;
}
sign = 1;
for (long j = 0; j <= 1607702095; j++) {
result2 += sign/(2 * j + 1);
sign *= -1;
}
System.out.println("result1 " + result1 * 4);
System.out.println("result2 " + result2 * 4);
System.out.println("pi " + Math.PI);
}
И результат:
result1 3.141592653576877
result2 3.1415926529660116
pi 3.141592653589793
Ответы
Ответ 1
На самом деле, ваш первый цикл имел бы int
переполнение при вычислении (2 * i + 1)
, когда i
достаточно велико, поэтому я не буду полагаться на его вывод.
Второй цикл, с другой стороны, создает более правильный вывод, поскольку (2 * j + 1)
не переполняется, поскольку он выполняет умножение long
.
Это означает, что "int-loop" вычисляет PI более точным, чем "длинный цикл"
Это, вероятно, просто совпадение, поскольку вычисления в переполнении цикла int
.
Ответ 2
Потому что вы переполняете строку
result1 += sign/(2 * i + 1);
Если значение 2*i
пересекает максимальное целочисленное значение
int range -2,147,483,648 to 2,147,483,647
, но когда вы делаете 2*i
для большего значения, он пересекает этот диапазон.
Лучше придерживаться long
, и это даст вам правильный результат.
Ответ 3
2 * i
, когда я близок к концу вашего цикла переполняет максимальное значение int, которое равно 2147483647
Использование длинной операции не переполняется.
Правильная процедура использует длинный тип. Вероятно, потому что значения добавляются и удаляются вокруг правильного PI для какого-то странного поведения, переполнение моментально вычисляет значение, близкое к правильному PI.
Я полагаю, что изменение предела цикла for из нескольких значений изменит конечный результат на значение, которое находится далеко от правого PI.
Ответ 4
У вас есть переполнение целых чисел.
Максимальная емкость подписанного int равна (2 ^ 31) -1 или 2,147,483,647.
(1,607,702,095 * 2) составляет 3215404190, что больше, чем 2,147,483,647.
Когда вы меняете я на длинный, вы увеличиваете емкость я до (2 ^ 63) -1.
Ответ 5
Заметили, что каждый указывает на переполнение целых чисел, но вам может понадобиться решение. (Если у вас уже есть один, пожалуйста, проигнорируйте следующее:))
При переполнении в части (2 * i + 1)
кода вам следует указать max i
в цикле for на (Integer.MAX_VALUE / 2 - 1)
, что приводит к:
for (int i = 0; i <= (Integer.MAX_VALUE / 2 - 1); i++) {
result1 += sign/(2 * i + 1);
sign *= -1;
}
Вы также можете сделать это в длинной части с помощью (Long.MAX_VALUE / 2 - 1)
, но он будет работать для ОЧЕНЬ ДЛИТЕЛЬНОГО времени.