我想将浮点值转换为int值或抛出异常,如果这种转换是不准确的。
我找到了以下建议:使用Math.round
来转换,然后使用==
来检查这些值是否相等。如果它们相等,那么转换是精确的,否则就不是。
但是我发现了一个不起作用的例子。下面是演示这个例子的代码:
String s = "2147483648";
float f = Float.parseFloat(s);
System.out.printf("f=%f\n", f);
int i = Math.round(f);
System.out.printf("i=%d\n", i);
System.out.printf("(f == i)=%s\n", (f == i));
它输出:
f=2147483648.000000
i=2147483647
(f == i)=true
我知道2147483648不适合整数范围,但我很惊讶=
为这些值返回true。有没有更好的方法来比较float和int?我想可以将这两个值都转换为字符串,但对于这样一个基本函数来说,这将非常缓慢。
浮动是相当不精确的概念。它们也基本上毫无意义,除非你现在运行的是相当旧的硬件,或者专门与浮点数工作的系统和/或协议进行交互,或者在它们的规范中有“使用浮点数”硬编码。这可能是真的,但如果不是,停止使用float,开始使用double——除非你有一个相当大的float[]
内存和性能差为零,否则float就不那么准确了。
当使用int
vsdouble
时,您的算法不会失败-所有int都可以完美地表示为double
。
这里潜在的错误是“无声铸造”的概念,以及java如何在那里采取了一些有意的自由。
在一般的计算机系统中,你只能比较同类。很容易用精确的位和机器码来表示,如果a和b是完全相同的类型,那么判断a==b是真是假意味着什么。当a和b是不同的东西时,这一点都不清楚。这一点几乎适用于任何运营商AB
,如果两者都是int
,则这是一种清晰易懂的操作。但是如果a
是char
,b
是,比如说,adouble
,那就完全不清楚了。
因此,在java中,所有涉及不同类型的二进制运算符都是非法的。例如,在BASIC中,没有字节码可以直接比较浮点和双精度,或者将字符串添加到int。
然而,还有语法糖:当你写a==b
时,其中a和b是不同的类型,而java确定其中一种类型是另一种类型的“子集”,那么java只需默默地将“较小”类型转换为“较大”类型,这样操作就可以成功。例如:
int x = 5;
long y = 5;
System.out.println(x == y);
这是可行的——因为java意识到将int
值转换为long
值是不会失败的,所以明确指定您希望代码这样做并不麻烦。在JLS术语中,这被称为扩大转换。相比之下,任何将“较大”类型转换为“较小”类型的尝试都是不合法的,您必须显式强制转换:
long x = 5;
int y = x; // does not compile
int y = (int) x; // but this does.
要点很简单:当你写上述相反的代码(intx=5;long y=x;
)时,代码是相同的,只是编译器在不会发生丢失的基础上,默默地为你注入了(long)
。同样的事情也发生在这里:
int x = 5;
long y = 10;
long z = x + y;
之所以编译,是因为javac
为您添加了一些语法糖,具体来说,编译时就像它说的那样:long z=((long)x)y
。表达式
xy
的“类型”是long
。
这里是关键技巧:Java考虑将int转换为float,以及将int或long转换为double-a。
与中一样,javac只会假设它可以安全地完成这项工作,而不会造成任何损失,因此不会强制程序员通过手动添加强制转换来明确确认。但是,int-
浮点数可以表示-2^23到2^23之间的每个整数值,双精度浮点数可以表示-2^52到2^52之间的每个整数值(源)。但是
int
可以表示-2^31
到2^31-1
,以及长-2^63
到2^63-1
之间的每个整数值。这意味着在边缘(非常大的负数/正数),存在整数,它们可以用整数表示,但不能用浮点数表示,或者用长整数表示,但不能用双精度表示(幸运的是,所有整数都可以用双精度表示;int-
这里就是这样:
(f==i)
被语法糖化为(f==((float)i))
,从int到float的转换引入了舍入。
大多数情况下,当你使用双精度和浮点数,却希望得到准确的数字时,你已经搞砸了。从根本上说,这些概念并不精确,这种精确性不能通过试图解释误差带而被附带进来,因为由于float和double的舍入行为而引入的误差无法被跟踪(无论如何都不容易)。因此,不应使用float/double。找到一个原子单位,用int/long表示,或者使用
BigDecimal
。(例如:编写记账软件时,不要将财务金额存储为双精度
。请将其存储为长格式的“美分”(或satoshis、日元、便士或该货币中的任何原子单位),或者,如果您真的知道自己在做什么,请使用
大十进制
)。
如果你绝对肯定在这里使用float(甚至double)是可以接受的,并且你仍然想要精确性,我们有一些解决方案。
选项1是使用BigDecimal的幂:
new BigDecimal(someDouble).intValueExact()
这是可行的,是100%可靠的(除非浮点到双精度的转换可以以某种方式将非精确值转换为精确值,我认为这不可能发生),并且抛出。速度也很慢。
另一种方法是利用我们对IEEE浮点标准工作原理的了解。
一个真正简单的答案是在编写算法时运行它,但是要添加一个额外的检查:如果你的
int
得到的值低于-2^23
或高于2^23
,那么它可能是不正确的。然而,在-2^23和2^23下面仍然有一些数字,它们在浮点数和int中都可以完美地表示,只是,不再是那个时候的每一个数字。如果你想要一个算法也能接受这些精确的数字,那么事情就变得复杂多了。我的建议是不要深究这个污水池:如果你有一个过程,你最终得到了一个接近这种极端的浮点数
,并且你想把它们变成int
,但只有在没有损失,你已经到达了一个疯狂的问题,你需要重新连接你得到的部分!
如果您真的需要它,我建议您使用
BigDecimal(),而不是尝试使用
如果你真的必须拥有这个技巧。float
。intValueExact()
我试图在Textpad中复制这个Java程序,但我收到以下错误 C:\Users\User\Desktop\java\Drawing.java:14: 错误: 不兼容的类型: 从 float 到 int g.drawLine ((getWidth()/2) , 0, (getWidth()*i) , (getHeight()/2)); 这是代码 在getWidth*i之前我已经尝试过添加(floa
问题内容: 我有以下代码,我想为浮点数指定一个十进制值而又不损失精度。 输出: 5.88 预期输出: 525.880005 问题答案: 仅具有7-8位有效数字。您的示例中的“ 5”是第9位数字。 即使它具有足够的精度,我也不知道525.880005是否可以精确表示为二进制浮点数。大多数十进制值不是:) 如果确切的十进制表示形式对您很重要,则应使用。
我一直在尝试编译,并玩了一圈的和数,但仍然不能弄清楚错误是什么。有什么想法吗? 标题:
之前,我已经实施了此功能,并且它起到了作用: 我甚至可以用下面的东西检查我是否得到了正确的尺寸,一切都很好。 但是,在使用以下初始化尝试整个程序时,我得到了一个编译错误: 以下是错误消息: rbm. cpp:在函数“ululemexFunction(int, mxArray**, int, const mxArray**)”中:rbm. cpp: 570:64: error:从“int”到“int
我想在Swift中将转换为。像这样的基本强制转换不起作用,因为这些类型不是原语,不像Objective-C中的s和s
问题内容: 我想将转换成斯威夫特。像这样的基本转换不起作用,因为这些类型不是基元,这与Objective-C中的s和s 不同 但这会产生以下错误消息: “浮点数”不可转换为“整数” 知道如何将属性从转换为吗? 问题答案: 您可以转换到斯威夫特这样的: 您还可以使用@paulm的注释来实现此结果: