Java中的浮点型和双精度型数据类型

254

浮点数据类型是单精度32位IEEE 754浮点数,双精度数据类型是双精度64位IEEE 754浮点数。

这意味着什么?我应该在什么情况下使用float而不是double,反之亦然?


10
内存使用关键时,应使用浮点数而不是双精度。如果需要更精确的计算,请使用双精度。 - Everv0id
16
@Everv0id说:“我不确定是否存在这样的情况,即内存非常紧张以至于人们必须为了节省空间而牺牲准确性。(你用的是Java,老天保佑...)可能有一些情况需要这样做,但在我的实践中很少见。如果你想详细说明为什么认为这是一个好主意,提供一个具体例子会是一个有价值的补充。” - Makoto
7
@Makoto 实际上,我从未使用过浮点数,只使用双精度数。但是,在理论上可能会有需要保存大量浮点数的应用程序,因此2倍的内存使用可能是关键性的。当然,这只是在理论上;在实践中,你总是可以购买另一台服务器 - Everv0id
我的意思是,在Java中,您可以通过硬件方式解决内存消耗问题。这比花费大量时间进行低级别的优化更容易且通常更便宜。 - Everv0id
3
我曾使用4字节甚至2字节的固定精度数字来节省内存,但是除非你需要保存数十亿个这样的数字,否则这样做很可能不值得。与使用额外内存相比,用"double"代替"float"多敲一个字母的时间价值要高1000倍。但是如果使用double而不是float可避免精度相关的错误,那就值得这样做。 - Peter Lawrey
显示剩余3条评论
9个回答

296

了解更多关于浮点数的内容,可以参考维基百科页面

总结如下:

  • float 占用 32 位,其中包括 1 个符号位、8 个指数位和 23 个尾数位(或从科学记数法得出的数字:2.33728*1012;33728 即为尾数)。

  • double 占用 64 位,其中包括 1 个符号位、11 个指数位和 52 个尾数位。

默认情况下,Java 使用 double 来表示其浮点数(因此,文字量为 3.14 的文字被视为 double 类型)。它也是可以提供更大数字范围的数据类型,所以强烈建议使用 double 而不是 float

可能有一些库实际上会强制您使用 float,但通常情况下,除非您能保证结果小到可以适应 float预定范围,否则最好选择 double

如果需要精确度,例如不能有不准确的小数位(例如 1/10 + 2/10),或者在处理货币时(例如将 $10.33 表示为系统中的数字),则使用 BigDecimal 即可,它可以支持任意数量的精度,并且可以优雅地处理这种情况。


4
在给定的例子中,233728 不是尾数吗?我的意思是,整数部分存储在哪里? - JaLoveAst1k
1
@mathguy54:在科学计数法中,2将是整数部分,而.33728将是尾数。这里有相关参考资料。 - Makoto
6
我在搜索浮点数和双精度浮点数的信息时发现了这个内容,并需要评论一下:如果你处理的货币不涉及小数点以下的分数,使用BigDecimal是荒谬的。常见货币是离散数据,因此你应该使用整数数据类型。(这是年轻程序员经常犯的错误之一--由于我们用“.”来区分美元和美分,他们认为它是一个浮点值。但实际上并不是。) - Trixie Wolf
2
@TrixieWolf,您能更具体地说明一下吗?您是建议使用两个整数(整数部分和小数部分)吗?而且您在谈论常见的货币,那其他情况呢?一些金额的计算需要精确到6位小数,所以不能简单地使用“*100”。请明确一点,您的意见很重要。 - AxelH
9
除了在财务计算中存在小数点的地方,货币总是离散的。您可以使用一种整数类型来存储数据。因此,$5.34将被存储为534。在整数运算中,美元部分为val/100,美分部分为val%100,其中%指余数运算。即使货币具有更多小数位数,它仍应被存储为整数,因为它是离散的。即使它不是离散的,通常您也会大部分时间将其转换为离散存储,因为这样精确度更高,您不会因舍入误差而损失资金。 - Trixie Wolf
显示剩余7条评论

83

一个float可以提供大约6-7位小数精度,而double可以提供大约15-16位。此外,double的数字范围更大。

一个double需要8个字节的存储空间,而一个float只需要4个字节。


16

浮点数也叫实数,用于计算需要小数精度的表达式。比如求平方根、三角函数(正弦和余弦)等运算得到的结果需要使用浮点类型来保证精度。Java 实现了标准(IEEE-754)的浮点类型和运算符。它们分为两种:float 和 double,分别表示单精度和双精度数。它们的位数和范围如下:


   Name     Width in Bits   Range 
    double  64              1 .7e–308 to 1.7e+308
    float   32              3 .4e–038 to 3.4e+038


浮点型(float)

浮点型指定了一种单精度值,使用 32 位存储空间。在某些处理器上,单精度比双精度更快,并且只需要一半的存储空间,但是当值非常大或非常小时,单精度值会变得不准确。当您需要小数部分但不需要高度精确度时,浮点型变量非常有用。

以下是一些浮点型变量声明的示例:

float hightemp, lowtemp;


双精度型(double)

双精度型,由 double 关键字表示,使用 64 位存储一个值。在现代某些优化为高速数学计算的处理器上,双精度实际上比单精度更快。所有的三角函数,如sin()、cos()和sqrt()等返回双精度值。当您需要在多个迭代计算中保持精度,或者操作大值数字时,双精度型是最佳选择。


这篇回答清晰地阐述了我们应该何时使用float和double。为什么不呢? - Ye Win
9
在Java中,既不推荐使用float也不推荐使用double类型来处理货币,因为它们容易出现舍入误差。这篇文章详细介绍了其中的原因:http://www.javapractices.com/topic/TopicAction.do?Id=13。 - PPartisan
1
不,不,不,绝对不能将货币表示为浮点数/双精度浮点数。 - reducing activity

5

这将会产生错误:

public class MyClass {
    public static void main(String args[]) {
        float a = 0.5;
    }
}

/MyClass.java:3: 错误: 不兼容的类型: 可能会丢失精度,从double转换为float float a = 0.5;

这段代码无法正常工作。

public class MyClass {
    public static void main(String args[]) {
        double a = 0.5;
    }
}

这也可以完美地工作。
public class MyClass {
    public static void main(String args[]) {
        float a = (float)0.5;
    }
}

原因:Java默认将实数存储为double以确保更高的精度。

Double在计算过程中占用更多的空间,但更加精确;而float占用更少的空间,但精度较低。


float a = 0.5f; 你也可以只加(f),这样也可以正常工作。 - Vikrant Pandey

3

尽管如此,Java似乎偏向于使用double进行计算:

举个例子,我今天早些时候写的程序,在使用float时方法无法工作,但是当我将float替换为double(在NetBeans IDE中),它们现在可以正常工作了:

package palettedos;
import java.util.*;

class Palettedos{
    private static Scanner Z = new Scanner(System.in);
    public static final double pi = 3.142;

    public static void main(String[]args){
        Palettedos A = new Palettedos();
        System.out.println("Enter the base and height of the triangle respectively");
        int base = Z.nextInt();
        int height = Z.nextInt();
        System.out.println("Enter the radius of the circle");
        int radius = Z.nextInt();
        System.out.println("Enter the length of the square");
        long length = Z.nextInt();
        double tArea = A.calculateArea(base, height);
        double cArea = A.calculateArea(radius);
        long sqArea = A.calculateArea(length);
        System.out.println("The area of the triangle is\t" + tArea);
        System.out.println("The area of the circle is\t" + cArea);
        System.out.println("The area of the square is\t" + sqArea);
    }

    double calculateArea(int base, int height){
        double triArea = 0.5*base*height;
        return triArea;
    }

    double calculateArea(int radius){
        double circArea = pi*radius*radius;
        return circArea;
    }

    long calculateArea(long length){
        long squaArea = length*length;
        return squaArea;
    }
}

我今天也遇到了同样的问题。这个偏见背后可能是什么原因? - Shachi

1
根据IEEE标准,float是实数的32位表示,而double是64位表示。
在Java程序中,我们通常大多数情况下看到使用double数据类型。这只是为了避免溢出,因为使用double数据类型可以容纳的数字范围比使用float时更大。
此外,当需要高精度时,鼓励使用double。一些早期实现的库方法仍然需要使用float数据类型(这仅仅是因为它是使用float实现的,没有其他原因!)。
但是,如果您确定您的程序需要小数,并且使用float不会发生溢出,那么使用float将大大提高您的空间复杂度,因为float所需的内存只有double所需内存的一半。

0

这个例子演示了如何从Java中的浮点数中提取符号(最左边的位)、指数(接下来的8位)和尾数(最右边的23位)。

int bits = Float.floatToIntBits(-0.005f);
int sign = bits >>> 31;
int exp = (bits >>> 23 & ((1 << 8) - 1)) - ((1 << 7) - 1);
int mantissa = bits & ((1 << 23) - 1);
System.out.println(sign + " " + exp + " " + mantissa + " " +
  Float.intBitsToFloat((sign << 31) | (exp + ((1 << 7) - 1)) << 23 | mantissa));

同样的方法也可以用于 double 类型(11 位指数和 52 位尾数)。

long bits = Double.doubleToLongBits(-0.005);
long sign = bits >>> 63;
long exp = (bits >>> 52 & ((1 << 11) - 1)) - ((1 << 10) - 1);
long mantissa = bits & ((1L << 52) - 1);
System.out.println(sign + " " + exp + " " + mantissa + " " +
  Double.longBitsToDouble((sign << 63) | (exp + ((1 << 10) - 1)) << 52 | mantissa));

来源:http://s-j.github.io/java-float/


0
在普通的编程计算中,我们不使用float。如果我们确保结果范围在float数据类型的范围内,则可以选择float数据类型来节省内存。通常,我们使用double有两个原因:
  • 如果我们想将浮点数用作float数据类型,则方法调用者必须明确地加上F或f后缀,因为默认情况下,每个浮点数都被视为double。这增加了程序员的负担。如果我们将浮点数作为double数据类型使用,则不需要添加任何后缀。
  • Float是一种单精度数据类型,意味着它占用4个字节。因此,在大型计算中,我们将无法获得完整的结果。如果我们选择double数据类型,它占用8个字节,我们将获得完整的结果。

float和double数据类型都是专门设计用于科学计算的,其中近似误差是可以接受的。如果精度是最重要的问题,则建议使用BigDecimal类代替float或double数据类型。来源:Java中的Float和Double数据类型


0

在进行精确计算时,应该使用double而不是float,而在进行不太精确的计算时则应该使用float而不是double。Float仅包含十进制数,但double包含IEEE754双精度浮点数,使得它更容易包含和计算数字。希望这可以帮到你。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接