首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何确定数字在浮点数中是否准确可表示?

如何确定数字在浮点数中是否准确可表示?
EN

Stack Overflow用户
提问于 2018-10-08 15:20:30
回答 6查看 1.5K关注 0票数 5

由于浮点数是基-2数制,所以不可能直接表示0.24F,也不可能在没有循环十进制周期 (即1/3=0.3333...0.(3) )的情况下用十进制表示1/3

因此,当打印回十进制表示时,浮点数0.24F显示为0.23,并因四舍五入而发生更改:

代码语言:javascript
复制
println(0.24F) => 0.23999999463558197021484375

0.25F可以直接显示:

代码语言:javascript
复制
println(0.25F) => 0.25

但是,我如何确定一个数字是完全可以表示的呢?

代码语言:javascript
复制
isExactFloat(0.25F) ==> true
isExactFloat(0.24F) ==> false

也许Java已经具备了这样的功能?

UPD这里是一个代码,它显示范围为-4,4的浮点数及其内部表示形式:

代码语言:javascript
复制
public class FloatDestructure {
    public static void main(String[] args) {
        BigDecimal dec = BigDecimal.valueOf(-4000L, 3);
        BigDecimal incr = BigDecimal.valueOf(1L, 3);
        for (int i = 0; i <= 8000; i++) {
            double dbl = dec.doubleValue();
            floatDestuct(dbl, dec);
            dec = dec.add(incr);
        }

    }
    static boolean isExactFloat(double d) { return d == (float) d; }

    static void floatDestuct(double val, BigDecimal dec) {
        float value = (float) val;
        int bits = Float.floatToIntBits(value);
        int sign = bits >>> 31;
        int exp = (bits >>> 23 & ((1 << 8) - 1)) - ((1 << 7) - 1);
        int mantissa = bits & ((1 << 23) - 1);
        float backToFloat = Float.intBitsToFloat((sign << 31) | (exp + ((1 << 7) - 1)) << 23 | mantissa);
        boolean exactFloat = isExactFloat(val);
        boolean exactFloatStr = Double.toString(value).length() <= 7;
        System.out.println(dec.toString() + " " + (double) val + " " + (double) value + " sign: " + sign + " exp: " + exp + " mantissa: " + mantissa + " " + Integer.toBinaryString(mantissa) + " " + (double) backToFloat + " " + exactFloat + " " + exactFloatStr);
    }
}

当尾数为零时,浮点数肯定是精确的。但在其他情况下,比如-0.375-1.625,情况就不那么清楚了。

EN

回答 6

Stack Overflow用户

回答已采纳

发布于 2021-06-12 20:51:37

我想在这里分享这一职能。

代码语言:javascript
复制
// Determine whether number is exactly representable in double.
// i.e., No rounding to an approximation during the conversion.
// Results are valid for numbers in the range [2^-24, 2^52].

public static boolean isExactFloat(double val) {

    int exp2 = Math.getExponent(val);
    int exp10 = (int) Math.floor(Math.log10(Math.abs(val)));

    // check for any mismatch between the exact decimal and
    // the round-trip representation.
    int rightmost_bits = (52 - exp2) - (16 - exp10);

    // create bitmask for rightmost bits
    long mask = (1L << rightmost_bits) - 1;

    // test if all rightmost bits are 0's (i.e., no rounding)
    return (Double.doubleToLongBits(val) & mask) == 0;
}

编辑:上面的功能可能更短。

代码语言:javascript
复制
public static boolean isExactFloat(double val) {

    int exp2 = Math.getExponent(val);
    int exp10 = (int) Math.floor(Math.log10(Math.abs(val)));

    long bits = Double.doubleToLongBits(val);

    // test if at least n rightmost bits are 0's (i.e., no rounding)
    return Long.numberOfTrailingZeros(bits) >= 36 - exp2 + exp10;        
}

演示

票数 1
EN

Stack Overflow用户

发布于 2018-10-08 15:29:25

一般来说,这是不可能的。一旦数字被转换成浮动或双,它只是一个数字的近似值。所以你的输入不是精确的.

如果您有浮点数的确切版本,例如字符串格式,那么就可以设计一个函数,它可以告诉您浮点数或双值是否准确地表示字符串格式的数字。参见关于如何实现这样一个函数的下面的评论。

票数 2
EN

Stack Overflow用户

发布于 2018-10-08 15:25:40

从它创建一个BigDecimal并捕获java.lang.ArithmeticException,如果有一个不终止的十进制展开,它将抛出。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/52705419

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档