Double.IsNaN测试快100倍? [英] Double.IsNaN test 100 times faster?

查看:176
本文介绍了Double.IsNaN测试快100倍?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在 .NET源代码中发现了这个:它声称比 System.Double.IsNaN 快100倍。是否有理由不使用这个函数而不是 System.Double.IsNaN

 私有结构NanUnion 
{
[FieldOffset(0)] internal double DoubleValue;
[FieldOffset(0)]内部UInt64 UintValue;
}

//标准的CLR double.IsNaN()函数大约比我们自己的包装
//慢100倍,所以请确保使用DoubleUtil.IsNaN( )在性能敏感的代码。
//跟踪CLR改进的PS项目是DevDiv Schedule:26916.
// IEEE 754:如果参数是范围0x7ff0000000000001L到0x7fffffffffffffffL
//中的任何值,或者范围在0xfff0000000000001L到0xffffffffffffffffL,结果将是NaN。
public static bool IsNaN(double value)
{
NanUnion t = new NanUnion();
t.DoubleValue = value;

UInt64 exp = t.UintValue& 0xfff0000000000000;
UInt64 man = t.UintValue& 0x000fffffffffffff;

return(exp == 0x7ff0000000000000 || exp == 0xfff0000000000000)&& (man!= 0);
}

编辑:Still 根据.NET源代码 System.Double.IsNaN 的代码如下:
$ b $ pre $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ return $($($) (& d)& 0x7FFFFFFFFFFFFFFFL)> 0x7FF0000000000000L;



$ b $ div class =h2_lin>解决方案


声称比System.Double.IsNaN快100倍


是的, 是真正。你错过了时间机器知道什么时候做出这个决定。 Double.IsNaN()不习惯看起来像那样。来自SSCLI10的源代码:

$ $ p $ $ code $ public static bool IsNaN(double d)
{
//比较一个NaN与另一个数字总是假的,因此这两个条件都是错误的。
if(d <0d || d> = 0d){
return false;
}
返回true;



$ b

在32位的FPU上,很差如果 d 是NaN,只是芯片设计的一个方面,它在微代码中被视为例外。英特尔处理器手册对此几乎没有提及,除了记录跟踪浮点辅助数量的处理器性能计数器,并注意到微代码顺控器对非常规和NaN起作用,潜在地花费
数百个周期。不是64位代码的问题,它使用SSE2指令,没有这个perf命中。



一些代码可以自己看看: p>

  using System; 
使用System.Diagnostics;

类程序{
static void Main(string [] args){
double d = double.NaN;
for(int test = 0; test< 10; ++ test){
var sw1 = Stopwatch.StartNew();
bool result1 = false;
for(int ix = 0; ix <1000 * 1000; ++ ix){
result1 | = double.IsNaN(d);
}
sw1.Stop();
var sw2 = Stopwatch.StartNew();
bool result2 = false;
for(int ix = 0; ix< 1000 * 1000; ++ ix){
result2 | = IsNaN(d);
}
sw2.Stop();
Console.WriteLine({0} - {1} x {2}%,sw1.Elapsed,sw2.Elapsed,100 * sw2.ElapsedTicks / sw1.ElapsedTicks,result1,result2);

}
Console.ReadLine();

public static bool IsNaN(double d){
// NaN与另一个数字的比较总是为false,因此这两个条件都是错误的。
if(d <0d || d> = 0d){
return false;
}
返回true;






$ b

使用Double.IsNaN()版本得到了微型优化。这样的微观优化在框架中不是邪恶的,微软.NET程序员的巨大负担是,他们很少猜测他们的代码何时处于应用程序的关键路径中。





  00:00:00.0027095  - 00:00:00.2427242 x 8957%
00:00:00.0025248 - 00:00:00.2191291 x 8678%
00:00:00.0024344 - 00:00:00.2209950 x 9077%
00: 00:00.0024144 - 00:00:00.2321169 x 9613%
00:00:00.0024126 - 00:00:00.2173313 x 9008%
00:00:00.0025488 - 00:00:00.2237517 x 8778%
00:00:00.0026940 - 00:00:00.2231146 x 8281%
00:00:00.0025052 - 00:00:00.2145660 x 8564%
00:00:00.0025533 - 00:00:00.2200943 x 8619%
00:00:00.0024406 - 00:00:00.2135839 x 8751%


I found this in the .NET Source Code: It claims to be 100 times faster than System.Double.IsNaN. Is there a reason to not use this function instead of System.Double.IsNaN?

[StructLayout(LayoutKind.Explicit)]
private struct NanUnion
{
    [FieldOffset(0)] internal double DoubleValue;
    [FieldOffset(0)] internal UInt64 UintValue;
}

// The standard CLR double.IsNaN() function is approximately 100 times slower than our own wrapper,
// so please make sure to use DoubleUtil.IsNaN() in performance sensitive code.
// PS item that tracks the CLR improvement is DevDiv Schedule : 26916.
// IEEE 754 : If the argument is any value in the range 0x7ff0000000000001L through 0x7fffffffffffffffL 
// or in the range 0xfff0000000000001L through 0xffffffffffffffffL, the result will be NaN.         
public static bool IsNaN(double value)
{
    NanUnion t = new NanUnion();
    t.DoubleValue = value;

    UInt64 exp = t.UintValue & 0xfff0000000000000;
    UInt64 man = t.UintValue & 0x000fffffffffffff;

    return (exp == 0x7ff0000000000000 || exp == 0xfff0000000000000) && (man != 0);
}

EDIT: Still according to the .NET Source Code, the code for System.Double.IsNaN is the following:

public unsafe static bool IsNaN(double d)
{
    return (*(UInt64*)(&d) & 0x7FFFFFFFFFFFFFFFL) > 0x7FF0000000000000L;
}

解决方案

It claims to be 100 times faster than System.Double.IsNaN

Yes, that used to be true. You are missing the time-machine to know when this decision was made. Double.IsNaN() didn't used to look like that. From the SSCLI10 source code:

   public static bool IsNaN(double d)
   {
       // Comparisions of a NaN with another number is always false and hence both conditions will be false.
       if (d < 0d || d >= 0d) {
          return false;
       }
       return true;
   }

Which performs very poorly on the FPU in 32-bit code if d is NaN. Just an aspect of the chip design, it is treated as exceptional in the micro-code. The Intel processor manuals say very little about it, other than documenting a processor perf counter that tracks the number of "Floating Point assists" and noting that the micro-code sequencer comes into play for denormals and NaNs, "potentially costing hundreds of cycles". Not otherwise an issue in 64-bit code, it uses SSE2 instructions which don't have this perf hit.

Some code to play with to see this yourself:

using System;
using System.Diagnostics;

class Program {
    static void Main(string[] args) {
        double d = double.NaN;
        for (int test = 0; test < 10; ++test) {
            var sw1 = Stopwatch.StartNew();
            bool result1 = false;
            for (int ix = 0; ix < 1000 * 1000; ++ix) {
                result1 |= double.IsNaN(d);
            }
            sw1.Stop();
            var sw2 = Stopwatch.StartNew();
            bool result2 = false;
            for (int ix = 0; ix < 1000 * 1000; ++ix) {
                result2 |= IsNaN(d);
            }
            sw2.Stop();
            Console.WriteLine("{0} - {1} x {2}%", sw1.Elapsed, sw2.Elapsed, 100 * sw2.ElapsedTicks / sw1.ElapsedTicks, result1, result2);

        }
        Console.ReadLine();
    }
    public static bool IsNaN(double d) {
        // Comparisions of a NaN with another number is always false and hence both conditions will be false.
        if (d < 0d || d >= 0d) {
            return false;
        }
        return true;
    }
}

Which uses the version of Double.IsNaN() that got micro-optimized. Such micro-optimizations are not evil in a framework btw, the great burden of the Microsoft .NET programmers is that they can rarely guess when their code is in the critical path of an application.

Results on my machine when targeting 32-bit code (Haswell mobile core):

00:00:00.0027095 - 00:00:00.2427242 x 8957%
00:00:00.0025248 - 00:00:00.2191291 x 8678%
00:00:00.0024344 - 00:00:00.2209950 x 9077%
00:00:00.0024144 - 00:00:00.2321169 x 9613%
00:00:00.0024126 - 00:00:00.2173313 x 9008%
00:00:00.0025488 - 00:00:00.2237517 x 8778%
00:00:00.0026940 - 00:00:00.2231146 x 8281%
00:00:00.0025052 - 00:00:00.2145660 x 8564%
00:00:00.0025533 - 00:00:00.2200943 x 8619%
00:00:00.0024406 - 00:00:00.2135839 x 8751%

这篇关于Double.IsNaN测试快100倍?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆