Java 如何快速检查浮动中的double是否适合?(爪哇)

Java 如何快速检查浮动中的double是否适合?(爪哇),java,floating-point,Java,Floating Point,是否有一些算术或位运算可以检查 一个双人套间是否能在没有损失的情况下放入浮动套间 精确性 它不仅应该检查双量程是否正确 在浮动范围内,也就是没有尾数位 滚开 再见 附言:对于C#,这个问题回答了一半: 但是我需要一个适用于Java的解决方案。这个怎么样: double d = ...; if ((double)(float)d == d) { System.out.println(d + " fits into float!"); } 这个想法非常简单:我们首先将其转换为float,然后

是否有一些算术或位运算可以检查 一个双人套间是否能在没有损失的情况下放入浮动套间 精确性

它不仅应该检查双量程是否正确 在浮动范围内,也就是没有尾数位 滚开

再见

附言:对于C#,这个问题回答了一半: 但是我需要一个适用于Java的解决方案。

这个怎么样:

double d = ...;
if ((double)(float)d == d) {
   System.out.println(d + " fits into float!");
}
这个想法非常简单:我们首先将其转换为
float
,然后返回到
double
,并检查结果是否仍然相同。如果
d
不适合float,则在
(float)d
强制转换时会丢失一些精度,因此结果会不同

严格地说,由于比较运算符将隐式地执行此转换,因此不需要将转换回
double
,因此
(float)d==d
也可以


如果您担心它的性能,因为许多浮点操作比可比较的int操作慢得多:这在这里几乎不是问题。在现代CPU中,浮点和双精度之间的转换非常有效。它甚至可以矢量化!
SSE2
指令集中有
cvtpd2ps
cvtps2pd
指令,它们执行从双精度到浮点的转换,反之亦然(一次转换4个值)。这些指令在所有支持它们的英特尔CPU上的延迟为4个周期。4次转换的4个周期非常快。

一个直接的解决方案可能如下所示:

public class Scribble {
    public static void main(String[] args) {
        for (int i = 1; i <= 10; i++) {

            double d = 1d / ((double)i);
            float f = (float) d;

            boolean lossless = d == f;

            System.out.println(d + " can be converted " + (lossless ? "lossless" : "only with loss"));
        }
    }
}

编辑:速度比较显示,method2似乎是最快的:

 method1  |  method2  |  method3 
237094654 | 209365345 | 468025911
214129288 | 209917275 | 448695709
232093486 | 197637245 | 448153336
249210162 | 200163771 | 460200921
240685446 | 200638561 | 447061763
332890287 | 337870633 | 450452194
247054322 | 199045232 | 449442540
235533069 | 200767924 | 452743201
256274670 | 199153775 | 453373979
298277375 | 198659529 | 456672251
229360115 | 205883096 | 454198291
252680123 | 224850463 | 452860277
246047739 | 200070587 | 458091501
304270790 | 204517093 | 463688631
235058620 | 204675812 | 448639390
260565871 | 205834286 | 458372075
256008432 | 242574024 | 498943242
311210028 | 208080237 | 478777466
242014926 | 208995343 | 457901380
239893559 | 205111348 | 451616471
代码:

公共类涂鸦{
静态整数大小=1024*1024*100;
静态布尔值[]结果=新布尔值[大小];
静态双精度[]值=新双精度[尺寸];
公共静态void main(字符串[]args){
//产生价值
对于(int i=0;i
类似于将数字转换为
float
并返回到
double
并检查是否相等(
=
),
double.compare()也可以使用:

double d = 2/3.0;

// 0 means OK, d fits into float
if (Double.compare(d, (float) d) == 0)
    System.out.println("OK, fits into float.");
此外,由于将
浮点
双精度
进行比较会隐式地将
浮点
转换为
双精度
,因此我们可以简单地编写:

if ((float) d == d)
    System.out.println("OK, fits into float.");

如果您想知道您的双精度值是否符合浮点的最大和最小范围,您不能使用类似于
(float)d==d的强制转换,因为d可能符合浮点范围,但不必在强制转换后具有相同的小数

在这种情况下,您必须与
Float.MAX\u值
Float.MIN\u值

return d <= Float.MAX_VALUE && d >= Float.MIN_VALUE;
返回d=Float.MIN\u值;

为什么这是个好主意?当然,记忆不是你所关心的。它的技术理由是什么?例如,当连载数以百万计的双打时。如果您可以通过使用浮点来节省字节,那么您可能会获得大量的速度或空间缩减。在慢速网络或慢速媒体上尤其有趣,因为这是一种解决方案。但是仍然有点犹豫使用它,这意味着两个FOP。@CookieMonster:CPU的FPU通常相当快。将
double
截断为
float
对它来说是一项相当简单的任务。我怀疑任何魔法转移(如果存在的话)会比这更快。@CookieMonester:我查了矢量化施法指令的延迟。它们相当不错(参见我在答案中最后编辑的一段)。我没有未分区的延迟,但我很确定它们也同样快。这实际上是无用的,因为它对大多数分数无效。e、 g.
0.1==(float)0.1
返回
false
…@NasBanov:Yes,因为0.1不适合float。因此结果
false
是正确的。这里的参数是什么?假设d-f==0与d==f相同。应该在这里吗?如果使用d-f==0,可能需要非规范化。另见:“非规范化的需要”。但我仍然不确定在浮点和双精度之间的特殊情况下是否也会发生这种情况。这主要是测试数字是否可以用二进制浮点精确表示。“尾数丢失”不是一个很好的标准。例如,浮点数为1/3=0.333333,双精度为0.3333。我们失去了任何精确性吗?(示例不是真实的)。double不仅可以容纳比float大/小的数字,还具有更高的精度。
if ((float) d == d)
    System.out.println("OK, fits into float.");
return d <= Float.MAX_VALUE && d >= Float.MIN_VALUE;