OSX上用Java从大型long转换为float的错误?

时间:2014-07-04 01:13:20

标签: java math casting

我在OS / X上运行JDK 1.7,64位。我认为这是一个错误......因为它不会出现在Android上,也不会出现在Ubuntu Linux机器上。也许它特定于我的x86处理器(刚刚今年早些时候购买)......不确定。

基本上,我想要一个时间......以纳秒或毫秒......表示为浮点数。当我运行下面的代码,并将System.nanoTime()返回的long转换为float时,float保持不变。 System.currentTimeMillis()也会出现同样的问题。时间(很长)当然正在改变......但是浮动的时间是完全失败的。它甚至会失败,我手动输入1404434478024L。

        for (int i=0; i<10; i++) { 
//          long timeL = 1404434478024L;
            long timeL = java.lang.System.nanoTime();
//          long timeL = java.lang.System.currentTimeMillis();

            float timeF = timeL;
            System.out.printf("%d: TimeL is %d.  timeF is %f. ", i, timeL, timeF);  

            Long pTimeL = new Long(timeL);
            float timeF2 = pTimeL.floatValue();
            System.out.printf("   And timeF2 is %f.\n", timeF2);    
        } 

Output:

0: TimeL is 1404435840046330000.  timeF is 1404435888972234750.000000.    And timeF2 is 1404435888972234750.000000.
1: TimeL is 1404435840046601000.  timeF is 1404435888972234750.000000.    And timeF2 is 1404435888972234750.000000.
2: TimeL is 1404435840046870000.  timeF is 1404435888972234750.000000.    And timeF2 is 1404435888972234750.000000.
3: TimeL is 1404435840047149000.  timeF is 1404435888972234750.000000.    And timeF2 is 1404435888972234750.000000.
4: TimeL is 1404435840047417000.  timeF is 1404435888972234750.000000.    And timeF2 is 1404435888972234750.000000.
5: TimeL is 1404435840047690000.  timeF is 1404435888972234750.000000.    And timeF2 is 1404435888972234750.000000.
6: TimeL is 1404435840047959000.  timeF is 1404435888972234750.000000.    And timeF2 is 1404435888972234750.000000.
7: TimeL is 1404435840048230000.  timeF is 1404435888972234750.000000.    And timeF2 is 1404435888972234750.000000.
8: TimeL is 1404435840048517000.  timeF is 1404435888972234750.000000.    And timeF2 is 1404435888972234750.000000.
9: TimeL is 1404435840048813000.  timeF is 1404435888972234750.000000.    And timeF2 is 1404435888972234750.000000.

这是我提出的修复/解决方法。

        System.out.printf("\n Now, with the fix:\n");           
        for (int i=0; i<10; i++) { 
//          long timeL = 1404434478024L;
//          long timeL = java.lang.System.nanoTime();
            long timeL = java.lang.System.currentTimeMillis();
            timeL = timeL % 1000000;    
            // Eliminate the high-order word... 
            // That is, keep only the lower digits under 1,000,000 seconds.  

            float timeF = timeL;
            System.out.printf("%d: TimeL is %d.  timeF is %f. ", i, timeL, timeF);  

            Long pTimeL = new Long(timeL);
            float timeF2 = pTimeL.floatValue();
            System.out.printf("   And timeF2 is %f.\n", timeF2);    
        }

Output:

 Now, with the fix:
0: TimeL is 840049.  timeF is 840049.000000.    And timeF2 is 840049.000000.
1: TimeL is 840049.  timeF is 840049.000000.    And timeF2 is 840049.000000.
2: TimeL is 840049.  timeF is 840049.000000.    And timeF2 is 840049.000000.
3: TimeL is 840049.  timeF is 840049.000000.    And timeF2 is 840049.000000.
4: TimeL is 840050.  timeF is 840050.000000.    And timeF2 is 840050.000000.
5: TimeL is 840050.  timeF is 840050.000000.    And timeF2 is 840050.000000.
6: TimeL is 840050.  timeF is 840050.000000.    And timeF2 is 840050.000000.
7: TimeL is 840050.  timeF is 840050.000000.    And timeF2 is 840050.000000.
8: TimeL is 840051.  timeF is 840051.000000.    And timeF2 is 840051.000000.
9: TimeL is 840051.  timeF is 840051.000000.    And timeF2 is 840051.000000.

其他人想尝试运行上面的第一个代码摘录,让我知道timeF是否正在改变你?也就是说,你是否没有遇到我的问题?

而且,发生了什么?有没有比我提出的更好的解决方法?

而且,这是一个错误吗?在哪一层?

3 个答案:

答案 0 :(得分:2)

float长度为32位。 long 64位长。

主要问题是在两种类型之间进行转换时会丢失一些精度。更具体地说,明确涵盖了this case in the Java Language Specification

  

将int或long值的扩展转换为float或long   值加倍,可能导致精度损失 - 即结果   可能会丢失该值的一些最低有效位。在这   case,生成的浮点值将是正确舍入的   使用IEEE 754舍入到最接近模式的整数值的版本   (§4.2.4)。

您获得了"round-to-nearest"行为。

答案 1 :(得分:2)

这是误用float的情况,而不是错误。 float类型的精度有限,正常数字为24位,相当于7位十进制数字。您的long值在最重要的12位十进制数字中都是相同的,因此它们都会转换为相同的float

如果在你的时间间隔内有一个进位,那么抑制最重要的32位可能会产生不良影响。

System.nanoTime()没有绝对意义。只有相对价值和差异才有意义。我建议在转换为longdouble进行后续计算之前,从float中减去每个nanoTime结果的第一个nanoTime结果。

答案 2 :(得分:0)

我无法评论,所以我会把它写成答案:

这是我得到的输出:

0: TimeL is 19799440493105.  timeF is 19799440621568.000000.    And timeF2 is 19799440621568.000000.
1: TimeL is 19799461838486.  timeF is 19799461593088.000000.    And timeF2 is 19799461593088.000000.
2: TimeL is 19799462215508.  timeF is 19799461593088.000000.    And timeF2 is 19799461593088.000000.
3: TimeL is 19799462573212.  timeF is 19799461593088.000000.    And timeF2 is 19799461593088.000000.
4: TimeL is 19799462915822.  timeF is 19799463690240.000000.    And timeF2 is 19799463690240.000000.
5: TimeL is 19799463295259.  timeF is 19799463690240.000000.    And timeF2 is 19799463690240.000000.
6: TimeL is 19799463587157.  timeF is 19799463690240.000000.    And timeF2 is 19799463690240.000000.                    
7: TimeL is 19799463867585.  timeF is 19799463690240.000000.    And timeF2 is 19799463690240.000000.
8: TimeL is 19799464241890.  timeF is 19799463690240.000000.    And timeF2 is 19799463690240.000000.
9: TimeL is 19799464598084.  timeF is 19799463690240.000000.    And timeF2 is 19799463690240.000000.

上面的代码运行完美,但问题可能是你的时间太大而无法转换为浮点数,所以请尝试使用双打代码。

希望这会有所帮助: 经典