Различайте ноль и отрицательный ноль с помощью java.math.bigdecimal

Можно ли отличить new BigDecimal(-0D) от new BigDecimal(0D)?

Где разница между обоими нулями?

XtremeBaumer 11.04.2018 14:00

@XtremeBaumer Они разные. Double.doubleToLongBits(0D) дает 0, Double.doubleToLongBits(-0D) дает -9223372036854775808.

lexicore 11.04.2018 14:02

«Отрицательный» ноль - это побочный эффект формата хранения чисел. BigDecimal не использует подобные форматы. Хотя BigDecimal.ZERO.negate() действительно создает отдельный объект, он все равно не позволит вам что-либо с ним сделать.

M. Prokhorov 11.04.2018 14:12

@ М.Прохоров Положительный и отрицательный ноль имеют математическое значение при рассмотрении пределов и т.д .; они не только побочный эффект хранения. Тот факт, что IEEE-754 поддерживает их с плавающей запятой, объясняется этим математическим значением.

Mark Rotteveel 11.04.2018 14:30

@MarkRotteveel, IEEE-754 имеет это, потому что они хранят знак в первом бите, как я уже сказал, - побочный эффект выбранного формата хранения. Я бы никогда так не посмотрел на ноль. Это не "свойство" числа "знать", что к нему обращаются, поскольку тогда это не число (то есть не точка числового поля). В частности, это свойство ограничения.

M. Prokhorov 11.04.2018 14:40

@ M.Prokhorov Насколько я знаю, в IEEE-754 это не побочный эффект, это намеренное дизайнерское решение Уильяма Кахана из-за его полезных приложений. С таким же успехом они могли бы указать, что знаковый бит не должен быть установлен на ноль.

Mark Rotteveel 11.04.2018 14:47

@MArkRotteveel, я сомневаюсь, что это решение принято, потому что они на самом деле хотели, чтобы ноль мог обозначать приближение к нему, поскольку нигде не указывается причина. Я бы сказал, что это было сделано из-за существования устаревшей системы, настолько серьезной, что проще включить странное исключение в стандарт (как это делают многие, когда они пытаются унифицировать конкурирующие реализации), чем исправлять эту систему и все рябь, которая исходит от этого исправления.

M. Prokhorov 11.04.2018 14:55

Исправление: я углубился в это, и это не из-за устаревших систем, а потому, что не каждый результат вычислений может быть представлен в аритметике с плавающей запятой, учитывая точность этого числа, поэтому некоторые вычисления, которые производят очень маленькое число ( поэтому он не может быть представлен ничем, кроме нуля с заданной точностью), по крайней мере, должен сохранять свой знак. Это все еще относится к «недостаткам представления чисел», так что я думаю, что моя основная мысль все еще остается в силе.

M. Prokhorov 11.04.2018 14:59

@ M.Prokhorov Но это было намеренное дизайнерское решение Уильяма Кахана (главного архитектора IEEE-754) именно по этой причине, см., Например, hackernoon.com/negative-zero-bbd5fd790af3 и people.freebsd.org/~das/kahan86branch.pdf Эта первая ссылка также включает цитату, где он признает, что ему это не нравится, но это был выбор меньшего зла.

Mark Rotteveel 11.04.2018 15:04

@MarkRotteveel, да, это осознанное решение обойти ограничение памяти и ограничения, налагаемые выбранным форматом хранения для чисел. Суть в том, что он существует, потому что у формата IEEE-754 есть проблемы. Числовой формат BigDecimal не имеет таких проблем, поэтому ему не нужен знаковый ноль. Значит, его там нет.

M. Prokhorov 11.04.2018 15:10
3
10
1 765
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Невозможно отличить это, потому что java.math.BigDecimal знает только один ноль (*). В нем нет понятия положительного или отрицательного нуля.

Это связано с тем, что внутри BigDecimal используется BigInteger, а BigInteger также имеет только одну концепцию нуля. BigInteger ведет себя как целое число с дополнением до двух, а дополнение до двух имеет только один ноль.

См. Также этот комментарий в источниках BigInteger:

public class BigInteger extends Number implements Comparable<BigInteger> {
    /**
     * The signum of this BigInteger: -1 for negative, 0 for zero, or
     * 1 for positive.  Note that the BigInteger zero <em>must</em> have
     * a signum of 0.  This is necessary to ensures that there is exactly one
     * representation for each BigInteger value.
     */
    final int signum

*: Not entirely accurate, you can have multiple zeroes with differing scale, just not with differing sign

@ GuillaumeMassé Рассмотрение исходного кода BigDecimal и реализация библиотеки, которая обеспечивает преобразование между Decimal128 IEEE-754 (который имеет положительный и отрицательный ноль) в BigDecimal.

Mark Rotteveel 11.04.2018 14:09

@ GuillaumeMassé См. Реализацию BigDecimal. В обоих случаях significand - это 0, поэтому BigDecimal инициализируется с помощью intVal=BigInteger.ZERO, scale=0, intCompact=0, precision=1. Если significand - это 0, знак не учитывается.

lexicore 11.04.2018 14:09

«ноль BigInteger должен имеет знак 0. Это необходимо, чтобы гарантировать, что существует ровно одно представление для каждого значения BigInteger».

Patrick Parker 11.04.2018 14:10

В javadoc говорится:

A BigDecimal consists of an arbitrary precision integer unscaled value and a 32-bit integer scale.

The value of the number represented by the BigDecimal is therefore (unscaledValue × 10scale).

Поскольку существует только одно целочисленное значение для нуля, невозможно представить «минус ноль» как BigDecimal.


Внутренне стандартная реализация BigDecimal использует BigInteger для представления «немасштабированного значения». Хотя javadocs не включает эту деталь реализации как часть спецификации, приведенного выше определения достаточно, чтобы исключить любую реализацию, в которой было два различных значения для положительного и отрицательного нуля.

Конечно, для нуля может быть несколько значений; например 0 и 0.00 не равны. Это следует из определения BigDecimal::equals(Object).

Если бы было выбрано другое целочисленное представление, было бы вполне возможно иметь два (или более) нуля, поэтому вы можете утверждать, что только тот факт, что в нем используется целое число произвольной точности, не является достаточной причиной для наличия одного нуля. Это вариант реализации для использования BigInteger, и тот факт, что BigInteger реализован так, как будто это дополнение до двух, приводит к тому, что два BigDecimal имеют только один ноль (сам BigInteger мог быть реализован, чтобы различать положительный и отрицательный ноль, но они не так, чтобы он вел себя как дополнение до двух)

Mark Rotteveel 11.04.2018 14:26

Хммм ... спорно. Конечно, с математической точки зрения наличие двух или более различных значений нуля является нарушением. Обратите внимание, что в документации javadoc не говорится о «представлении» «немасштабированного значения». Он называет это целым числом, простым и понятным.

Stephen C 11.04.2018 14:30

При выполнении анализа, включающего пределы, имеющие положительный и отрицательный ноль, могут иметь математическое значение.

Mark Rotteveel 11.04.2018 14:32

Что касается «Он называет это целым, простым и понятным»., если бы Java использовала дополнение до единицы для своего целочисленного представления (или если бы BigInteger был реализован так, чтобы вести себя как дополнение), то BigDecimal, скорее всего, имел бы два нуля, поскольку целое число в дополнении до единицы действительно знает два нуля. Так что сам факт использования целого числа не является достаточной причиной. (Я знаю, это немного надуманный аргумент;)

Mark Rotteveel 11.04.2018 14:38

Да. Но я возвращаюсь к аргументу, что формулировка документации javadoc не говорит о представлении «немасштабированного значения». Целое число - это чисто математическое понятие ... не зависящее от представления. Дополнение до единицы - это (ошибочное) представление целых чисел. Это не целые числа как таковой.

Stephen C 11.04.2018 14:57

@MarkRotteveel, работая с ограничениями, вы на самом деле не работаете с числами - вы работаете с числовыми полями, а предел - это функция определенного вами поля, а не само число. Математически случай, когда может появиться знаковый ноль (деление на ноль), имеет смысл нуль (ха-ха), его результат не определен для действительных чисел.

M. Prokhorov 11.04.2018 15:22

Другие вопросы по теме