IEEE-754双(64位浮点)与长(64位整数)重新访问 [英] IEEE-754 Double (64-bit floating point) vs. Long (64-bit Integer) Revisited

查看:162
本文介绍了IEEE-754双(64位浮点)与长(64位整数)重新访问的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在重新审视一个问题(如何测试数值转换是否会改变价值?),就我而言完全解决了问题是检测特定数值何时会溢出JavaScript的IEEE-754号码类型。以前的问题是使用C#,标记的答案工作正常。

I'm revisiting a question (How to test if numeric conversion will change value?) that as far as I was concerned was fully solved. The problem was to detect when a particular numeric value would overflow JavaScript's IEEE-754 Number type. The previous question was using C# and the marked answer worked perfectly.

现在我正在完成相同的任务,但这次在Java中,它不起作用。 AFAIK,Java使用IEEE-754作为双重数据类型。所以我应该能够来回来强制精确度的损失,但它是一次次的。在这个封闭的时候,我开始在Java中深入挖掘,现在我真的很困惑。

Now I'm doing the exact same task but this time in Java and it doesn't work. AFAIK, Java uses IEEE-754 for its double data type. So I should be able to cast it back and forth to force the loss of precision but it round trips. Baffled by this I started poking deeper in Java and now I'm really confused.

在C#和Java中,long的最小值和最大值是相同的: / p>

In both C# and Java, the min and max values for long are the same:

long MIN_VALUE = -9223372036854775808L;
long MAX_VALUE = 9223372036854775807L;

AFAIK,这些值在IEEE-754中的可表示数字之外,因为为指数和符号。

AFAIK, these values are outside the representable numbers in IEEE-754 because of the fixed bits reserved for the exponent and sign.

// 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 for(value = -9223372036854775808L)在Java中:

This returns false for (value = -9223372036854775808L) in Java:

boolean invalidIEEE754(long value) {
    try {
        return ((long)((double)value)) != value;
    } catch (Exception ex) {
        return true;
    }
}

返回 false for(value = -9223372036854775808L)in Java:

This returns false for (value = -9223372036854775808L) in 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 for(value = -9223372036854775808L)但不太准确:

This returns true for (value = -9223372036854775808L) but is less accurate:

boolean invalidIEEE754(long value) {
    return (0x0L != (0xFFF0000000000000L & (value < 0L ? -value : value)));
}

为什么这样工作?我错过了一些编译器优化,例如编译器是否检测到我的转换,并为我修改

Why does this work this way? Am I missing something like compiler optimization, e.g. is the compiler detecting my conversions and "fixing" them for me?

编辑:根据请求添加测试用例。所有这三个测试失败:

Adding test case by request. All three of these tests fail:

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);
    }
}


推荐答案

code> -9223372036854775808L 可表示为IEEE-754双精度数字。它正是 -2 ^ 63 ,它具有双重表示 -1.0 x 2 ^ 63 和编码 0xc3e0000000000000

-9223372036854775808L is representable as an IEEE-754 double-precision number. It is exactly -2^63, which has the double representation -1.0 x 2^63 and encoding 0xc3e0000000000000.

双重能够表示数字,远远大于此值。但是,它不能在可表示数字范围内表示所有整数。例如,如果您添加一个数字,您将获得 -9223372036854775807 = -2 ^ 63 + 1 ,这是可表示为双精度值,并且不能在往返转换中生存。

Double is capable of representing numbers much, much larger than this. However, it is not capable of representing all integers in the range of representable numbers. For example, if you add one to the number, you will get -9223372036854775807 = -2^63 + 1, which is not representable as a double-precision value, and will not survive the round-trip conversion.

转换 -2 ^ 63 + 1 将其加倍到最接近的可表示的双重值,即 -2 ^ 63 ;转换回长时间将保留该值。

Converting -2^63 + 1 to double will round it to the nearest representable double value, which is -2^63; conversion back to long will preserve that value.

编辑:您在JavaScript测试中执行了哪些平台?在当前的Safari中,

What platform did you do you JavaScript test on? In current Safari,

"-9223372036854775808" === Number(-9223372036854775808).toFixed()

评估为 True

这篇关于IEEE-754双(64位浮点)与长(64位整数)重新访问的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆