bero1985

Branch-less SSE-less Flush-Denormals/NaNs/INFs-to-Zero

Jun 29th, 2011
205
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Delphi 2.62 KB | None | 0 0
  1.  
  2. {
  3.  
  4. // Branch-less SSE-less Flush-Denormals/NaNs/INFs-to-Zero
  5. // By Benjamin 'BeRo' Rosseaux - benjamin[at]rosseaux[dot]com
  6.  
  7. ///////////////////////////////////////////
  8. // ObjectPascal data types for C/C++lers //
  9. ///////////////////////////////////////////
  10. //                                       //
  11. // longword=32-bit unsigned int          //  
  12. // longint=32-bit signed int             //
  13. // single=32-bit float                   //
  14. //                                       //
  15. ///////////////////////////////////////////
  16.  
  17. How the trick does work:
  18.  
  19. }
  20.  
  21. // The exponent of a float is 8-bit width (the 9-bit would be the sign bit). So:
  22.  
  23. var Value:single;
  24.     Exponent:longword;
  25.  
  26. longword(Exponent):=(longword(pointer(@Value)^) shr 23) and $ff;
  27.  
  28. // longword(Exponent) is now 0 for Denormals and 255 for NaNs/INFs and 1-254 for all other values, so:
  29.  
  30. longword(Exponent):=(longword(Exponent)+1) and $ff;
  31.  
  32. // longword(Exponent) is now 1 for Denormals and 0 for NaNs/INFs and 2-255 for all other values, so:
  33.  
  34. longword(Exponent):=longword(Exponent)-2;
  35.  
  36. // longint(Exponent) is now -2 for Denormals and -1 for NaNs/INFs and 0-253 for all other values, so
  37. // extract the sign bit:
  38.  
  39. longword(Exponent):=longword(Exponent) shr 31;
  40.  
  41. // longint(Exponent) is now 1 for Denormals and 1 for NaNs/INFs and 0 for all other values, so:
  42.  
  43. longword(Exponent):=$ffffffff+longword(Exponent);
  44.  
  45. // longint(Exponent) is now 0 for Denormals and 0 for NaNs/INFs and $ffffffff for all other other, so
  46. // apply it simply as bitwise-and-mask to the float value:
  47.  
  48. longword(pointer(@Value)^):=longword(pointer(@Value)^) and longword(Exponent);
  49.  
  50. // Optimized without the bloated shift-right-by-23-stuff etc. the code will get it so:
  51.  
  52. longword(pointer(@Value)^):=longword(pointer(@Value)^) and longword($ffffffff+longword(((((longword(pointer(@Value)^) and $7f800000)+$800000) and $7f800000)-$1000000) shr 31));
  53.  
  54. // or as x86-ASM code:
  55.  
  56. asm
  57.  mov eax,dword ptr Value
  58.  and eax,$7f800000
  59.  add eax,$00800000
  60.  and eax,$7f800000
  61.  sub eax,$01000000
  62.  shr eax,31
  63.  dec eax
  64.  and dword ptr Value,eax
  65. end;
  66.  
  67. // or as handly drop-in ready-to-use function: (define caninline, if you do use FreePascal or a Delphi version, which supports function-inlining)
  68.  
  69. function KillDenormal(const Value:single):single; {$ifdef caninline}inline;{$endif}
  70. begin
  71.  // Branch-less SSE-less Flush-Denormals/NaNs/INFs-to-Zero function
  72.  // By Benjamin 'BeRo' Rosseaux - benjamin[at]rosseaux[dot]com
  73.  longword(pointer(@result)^):=longword(pointer(@Value)^) and longword($ffffffff+longword(((((longword(pointer(@Value)^) and $7f800000)+$800000) and $7f800000)-$1000000) shr 31));
  74. end;
Advertisement
Add Comment
Please, Sign In to add comment