Фактическое значение y
в вашей последней итерации составляет около -2,1 • 10 −8 (иногда отображается как «-2.1e-8» или «-.000000021»).Он отображается как «-0,00», потому что вы напечатали его ограниченным количеством цифр.Это означает, что заголовок вашего вопроса не соответствует цели: нет -0.0
для преобразования в 0.0
.На самом деле у вас есть небольшое отрицательное значение, а не -0
.
Другие ответы предлагают обходные пути, такие как ручное тестирование небольшого значения и замена его на ноль.Хотя простые обходные пути могут работать в конкретном случае, о котором вы спрашиваете, они являются грубыми предложениями (например, принимают абсолютное значение или сравнивают абсолютное значение с 0.5e-2
) с некоторыми недостатками.Например, в последнем случае, правильный тест Math.abs(y) <= 0.5e-2
или Math.abs(y) < 0.5e-2
?Знание того, использовать ли <
или <=
, требует знания, округляется ли исходный текст 0.5e-2
в большую или меньшую сторону путем преобразования в double
.Хотя это легко определить для конкретного значения (печатая полное десятичное значение результата преобразования и визуально сравнивая его с 0,05 - затем используйте <=
, если результат меньше 0,05, и <
, если оно выше),это не так просто для ценностей в целом.Один правильный способ получить результат, отформатированный по вашему желанию, - это распечатать в буфер, затем проверить результат, чтобы увидеть, содержит ли он только ноль цифр, а затем, если он есть, заменить «-» на пробел.
Вы должны понимать, что вы пытаетесь исправить не то, что здесь.Нет ничего плохого в том, что перед нулем стоит отрицательный знак.Это, однако, признак того, что в вашей программе другие вещи неправильны.
Java использует двоичный формат для чисел с плавающей запятой.В этом формате 0,1 не может быть точно представлено, и это означает, что значение x
в вашем цикле никогда не будет точно кратным 0,1, за исключением первой итерации, когда оно начинается с 1.
В Java,исходный текст 0.1
преобразуется в ближайшее представимое значение, равное 0,1000000000000000055511151231257827021181583404541015625.(Хотя я записал это значение со многими десятичными цифрами, это ровно 53-разрядное целое число, деленное на степень два.) На первой итерации вашего цикла x
имеет значение 0,90000000000000002220446049250313080847263336181640625.На последней итерации оно имеет значение -0,999999999999997779553950749686919152736663818359375.Так как это последнее значение не точно равно -1, y
не совсем равно нулю.
Серьезная проблема здесь заключается в том, что, когда вы пишете цикл, подобный этому, не гарантируется, что он закончится значением, близким к -1, если вы используете другой размер шага.Каждый раз, когда вы выполняете арифметику с плавающей запятой, точный математический результат округляется до ближайшего представимого значения, и это округление может привести к увеличению или уменьшению значения.Рассмотрим, что происходит, когда цикл приближается к концу, и добавление к x
дает -1,0000000000000002… вместо −0,99999999999999997… Тогда тест x >= -1
сообщает об ошибке, и цикл не выполняет ожидаемую последнюю итерацию.Например, если размер шага был 0,01 вместо 0,1, последняя итерация была бы с x
равной -0,99000000000000143440814781570225022733211517333984375.Последняя итерация, где x
должна быть близка к -1, никогда не выполняется, поскольку фактическое вычисленное значение для x
равно -1,000000000000001332267629550187848508358001708984375.
Классический способ избежать этой проблемы в простых циклах - использоватьарифметика без ошибок округления для управления циклом, а затем масштабируйте значение итератора до желаемого диапазона.В вашем случае вы можете использовать:
for (i = 10; i >= -10; i -= 1)
{
x = i / 10.;
…
}
Здесь i
может быть целочисленным типом или типом с плавающей точкой.Поскольку все целые числа представимы в Java от double
до 2 53 , в этом диапазоне нет ошибок округления для арифметики с целочисленными результатами.