Як перевірити, позитивний чи від’ємний нуль?


77

Чи можна перевірити, чи a floatє позитивним нулем (0,0) чи негативним нулем (-0,0)?

Я перетворив floata на Stringі перевірив, чи є перший chara '-', але чи існують інші способи?


8
Перевірки знакового біта (крайнього лівого біта) має бути достатньо
boxed__l

6
Дійсно, нуль не є ні від’ємним, ні позитивним числом.
Grijesh Chauhan

21
@GrijeshChauhan: Тільки теоретично
Мукінг Качка

10
@fridge: але питання не в математиці, а в Java. Будь-яке відношення, яке можуть мати значення з плаваючою крапкою до чисел, є людським задумом і може спричинити негерметичні абстракції ;-)
Стів Джессоп,

3
Можливо, це дурне запитання, але мені було просто цікаво: чому потрібно розрізняти позитивне і негативне 0?
siegi

Відповіді:


80

Так, розділіть на це. 1 / +0.0fє +Infinity, але 1 / -0.0fє -Infinity. Легко дізнатися, який це, за допомогою простого порівняння, ви отримаєте:

if (1 / x > 0)
    // +0 here
else
    // -0 here

(це передбачає, що це xможе бути лише один із двох нулів)


6
Чи не було б простіше перенести знак нуля на інше число, скажімо 1.0, за допомогою Math.copySign? Напр.if (math.copySign (1.0, x) < 0.0) ...
нюффа

3
@njuffa: Не впевнений, як math.copySign(1.0,x)<0.0це "простіше", ніж 1/x>0. Я маю на увазі, що обидва цілком не зрозумілі, тому ви все одно хочете мати для цього функцію
Ніклас Б.

2
@njuffa: Так, я вважав, що у вас є відповіді на читаність з цією відповіддю;) Я не вважав поділ важким, оскільки, мабуть, є особливий випадок для нульових дільників
Ніклас Б.

1
Ну, якщо ви, хлопці, хочете дізнатися, наскільки це важко, тоді .. це залежить. Наприклад, передача знаків дратує з інструкціями x87, але чудово з SSE. І скільки часу триває поділ, він коливається від 9 (я думаю?) До понад ста циклів (залежно від розділених значень та µarch). Будь-хто міг перемогти, і це лише на системах x86.
harold 14.03.14

1
Якщо ви просто бажаєте ефективності, чи не найкращим рішенням буде перетворення його на int та допит знакового біта? Я не впевнений, наскільки ефективно ви можете це зробити в Java, але в більшості архітектур це можна зробити просто за допомогою інструкції АБО, за якою слідує інструкція стрибка нуля або стрибка не нуля, і АБО зазвичай одноциклова. Умовна вартість стрибка сильно відрізняється залежно від архітектури.
reirab

39

Ви можете скористатися Float.floatToIntBitsдля перетворення його у формат an intі розглянути бітову схему:

float f = -0.0f;

if (Float.floatToIntBits(f) == 0x80000000) {
    System.out.println("Negative zero");
}

Набагато краще, ніж ділення, яке може зайняти кілька тактових циклів і може затримати стан переповнення в блоці FPU. А ще краще:(Float.floatToIntBits(f) & 0x80000000) < 0
Марк Єронімус

12

Безумовно, не найкращий підхід. Оформити функцію

Float.floatToRawIntBits(f);

Доку:

/**
 * Returns a representation of the specified floating-point value
 * according to the IEEE 754 floating-point "single format" bit
 * layout, preserving Not-a-Number (NaN) values.
 *
 * <p>Bit 31 (the bit that is selected by the mask
 * {@code 0x80000000}) represents the sign of the floating-point
 * number.
 ...
 public static native int floatToRawIntBits(float value);

10

Double.equalsвідрізняє ± 0,0 на Java. (Є також Float.equals.)

Я трохи здивований, що про них ніхто не згадував, оскільки вони здаються мені зрозумілішими за будь-який із методів, наведених дотепер!


Це справді зрозуміліше; однак, можливо, вам не доведеться виділяти два об'єкти в купі лише для порівняння двох значень.
Klitos Kyriacou

7

Підхід, що використовується, Math.minподібний до того, що пропонує Єспер, але трохи чіткіший:

private static int negativeZeroFloatBits = Float.floatToRawIntBits(-0.0f);

float f = -0.0f;
boolean isNegativeZero = (Float.floatToRawIntBits(f) == negativeZeroFloatBits);

6

Коли плаваючий знак від’ємний (включаючи -0.0та -inf), він використовує той самий розрядний біт, що і мінус int. Це означає, що ви можете порівняти цілочисельне представлення 0, усуваючи необхідність знати або обчислювати цілочисельне представлення -0.0:

if(f == 0.0) {
  if(Float.floatToIntBits(f) < 0) {
    //negative zero
  } else {
    //positive zero
  }
}

Це має додаткову гілку над прийнятою відповіддю, але я думаю, що це читабельніше без шістнадцяткової константи.

Якщо ваша мета - просто розглядати -0 як від’ємне число, ви можете залишити зовнішнє ifтвердження:

if(Float.floatToIntBits(f) < 0) {
  //any negative float, including -0.0 and -inf
} else {
  //any non-negative float, including +0.0, +inf, and NaN
}

0

Для негативних:

new Double(-0.0).equals(new Double(value));

Позитивні:

new Double(0.0).equals(new Double(value));
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.