Я возвращаюсь к вопросу (How to test if numeric conversion will change value?), который, насколько я был заинтересован, был полностью решен. Проблема заключалась в обнаружении, когда определенное числовое значение переполнило бы тип номера IEEE-754 типа JavaScript. В предыдущем вопросе использовался C#, и отмеченный ответ работал отлично.IEEE-754 Двойная (64-разрядная плавающая точка) по сравнению с длинным (64-разрядное целое). Повторно рассмотрен
Теперь я выполняю ту же задачу, но на этот раз в Java, и она не работает. AFAIK, Java использует IEEE-754 для своего двойного типа данных. Поэтому я должен был бы отбросить его назад и вперед, чтобы заставить потеря точности, но это круговые поездки. Сбитый с толку, я начал глубже натыкаться на Java, и теперь я действительно смущен.
В обеих C# и Java, минимальное и максимальное значение для длины одинаково:
long MIN_VALUE = -9223372036854775808L;
long MAX_VALUE = 9223372036854775807L;
AFAIK, эти значения находятся за пределами представимых чисел в IEEE-754 из-за фиксированные биты, зарезервированных для показателя и знак.
// this fails in browsers that have stuck with the pure ECMAScript Number format
var str = Number(-9223372036854775808).toFixed();
if ("-9223372036854775808" !== str) { throw new Error("Overflow!"); }
Это возвращает false
для (значение = -9223372036854775808L) в Java:
boolean invalidIEEE754(long value) {
try {
return ((long)((double)value)) != value;
} catch (Exception ex) {
return true;
}
}
Это возвращает false
для (значение = -9223372036854775808L) в Java:
boolean invalidIEEE754(long value) {
// trying to get closer to the actual representation and
// being more explicit about conversions
long bits = Double.doubleToLongBits(Long.valueOf(value).doubleValue());
long roundtrip = Double.valueOf(Double.longBitsToDouble(bits)).longValue();
return (value != roundtrip);
}
Это возвращает true
для (значение = -9223372036854775808L), но менее точно:
boolean invalidIEEE754(long value) {
return (0x0L != (0xFFF0000000000000L & (value < 0L ? -value : value)));
}
Почему это так работает? Я упускаю что-то вроде оптимизации компилятора, например. компилятор обнаруживает мои конверсии и «фиксирует» их для меня?
Редактировать: Добавление тестового образца по запросу. Все три из этих тестов не в состоянии:
import static org.junit.Assert.*;
import org.junit.Test;
public class FooTests {
@Test
public void ieee754One() {
assertTrue(((long)((double)Long.MIN_VALUE)) != Long.MIN_VALUE);
}
@Test
public void ieee754Two() {
long bits = Double.doubleToLongBits(Long.valueOf(Long.MIN_VALUE).doubleValue());
long roundtrip = Double.valueOf(Double.longBitsToDouble(bits)).longValue();
assertTrue(Long.MIN_VALUE != roundtrip);
}
@Test
public void ieee754Three() {
long bits = Double.doubleToRawLongBits(Long.valueOf(Long.MIN_VALUE).doubleValue());
long roundtrip = Double.valueOf(Double.longBitsToDouble(bits)).longValue();
assertTrue(Long.MIN_VALUE != roundtrip);
}
}
Оба метода возвращают `false` для меня. JDK 1.6.0_21. – axtavt 2010-12-03 19:37:50
Интересно! Теперь я действительно смущен. Шахта работает через JUnit, но также должна быть на JDK 1.6.0_21. – mckamey 2010-12-03 19:42:06