hedgewars/uFloat.pas
branchhedgeroid
changeset 15532 7030706266df
parent 11046 47a8c19ecb60
child 15649 ea189ee9394f
--- a/hedgewars/uFloat.pas	Sun Oct 28 15:18:26 2012 +0100
+++ b/hedgewars/uFloat.pas	Fri Dec 06 22:20:53 2019 +0100
@@ -1,6 +1,6 @@
 (*
  * Hedgewars, a free turn based strategy game
- * Copyright (c) 2004-2012 Andrey Korotaev <unC0Rr@gmail.com>
+ * Copyright (c) 2004-2015 Andrey Korotaev <unC0Rr@gmail.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -13,7 +13,7 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  *)
 
 {$INCLUDE "options.inc"}
@@ -39,7 +39,6 @@
  *)
 interface
 
-{$IFDEF FPC}
 {$IFDEF ENDIAN_LITTLE}
 type hwFloat = record
     isNegative: boolean;
@@ -85,8 +84,8 @@
 function hwRound(const t: hwFloat): LongInt; inline; // Does NOT really round but returns the integer representation of the hwFloat without fractional digits. (-_0_9 -> -0, _1_5 -> _1)
 function hwAbs(const t: hwFloat): hwFloat; inline; // Returns the value of t with positive sign.
 function hwSqr(const t: hwFloat): hwFloat; inline; // Returns the square value of parameter t.
-function hwPow(const t: hwFloat; p: LongWord): hwFloat; inline; // Returns the power of the value
-function hwSqrt(const t: hwFloat): hwFloat; inline; // Returns the the positive square root of parameter t.
+function hwSqrt1(const t: hwFloat): hwFloat; inline; // Returns the the positive square root of parameter t.
+function hwSqrt(const x: hwFloat): hwFloat; inline; // Returns the the positive square root of parameter t.
 function Distance(const dx, dy: hwFloat): hwFloat; // Returns the distance between two points in 2-dimensional space, of which the parameters are the horizontal and vertical distance.
 function DistanceI(const dx, dy: LongInt): hwFloat; // Same as above for integer parameters.
 function AngleSin(const Angle: Longword): hwFloat;
@@ -96,14 +95,9 @@
 function hwSign(r: hwFloat): LongInt; inline; // Returns an integer with value 1 and sign of parameter r.
 function hwSignf(r: real): LongInt; inline; // Returns an integer with value 1 and sign of parameter r.
 function isZero(const z: hwFloat): boolean; inline;
-{$IFDEF FPC}
-{$J-}
-{$ENDIF}
+
 {$WARNINGS OFF}
-
-
 // some hwFloat constants
-
 const  _1div1024: hwFloat = (isNegative: false; QWordValue:     4194304);
       _1div10000: hwFloat = (isNegative: false; QWordValue:      429496);
       _1div50000: hwFloat = (isNegative: false; QWordValue:       85899);
@@ -151,20 +145,20 @@
           _0_999: hwFloat = (isNegative: false; QWordValue:  4290672328);
               _0: hwFloat = (isNegative: false; QWordValue:           0);
               _1: hwFloat = (isNegative: false; QWordValue:  4294967296);
-            _1_2: hwFloat = (isNegative: false; QWordValue:  1288490189*4);
+            _1_2: hwFloat = (isNegative: false; QWordValue:  4294967296 * 6 div 5 + 1);
             _1_5: hwFloat = (isNegative: false; QWordValue:  4294967296 * 3 div 2);
             _1_6: hwFloat = (isNegative: false; QWordValue:  4294967296 * 8 div 5);
             _1_9: hwFloat = (isNegative: false; QWordValue:  8160437862);
               _2: hwFloat = (isNegative: false; QWordValue:  4294967296 * 2);
             _2_4: hwFloat = (isNegative: false; QWordValue:  4294967296 * 12 div 5);
               _3: hwFloat = (isNegative: false; QWordValue:  4294967296 * 3);
-            _3_2: hwFloat = (isNegative: false; QWordValue:  3435973837*4);
+            _3_2: hwFloat = (isNegative: false; QWordValue:  4294967296 * 16 div 5);
              _PI: hwFloat = (isNegative: false; QWordValue: 13493037704);
               _4: hwFloat = (isNegative: false; QWordValue:  4294967296 * 4);
             _4_5: hwFloat = (isNegative: false; QWordValue:  4294967296 * 9 div 2);
               _5: hwFloat = (isNegative: false; QWordValue:  4294967296 * 5);
               _6: hwFloat = (isNegative: false; QWordValue:  4294967296 * 6);
-            _6_4: hwFloat = (isNegative: false; QWordValue:  3435973837 * 8);
+            _6_4: hwFloat = (isNegative: false; QWordValue:  4294967296 * 32 div 5);
               _7: hwFloat = (isNegative: false; QWordValue:  4294967296 * 7);
              _10: hwFloat = (isNegative: false; QWordValue:  4294967296 * 10);
              _12: hwFloat = (isNegative: false; QWordValue:  4294967296 * 12);
@@ -195,18 +189,11 @@
          cLittle: hwFloat = (isNegative: false; QWordValue:           1);
          cHHKick: hwFloat = (isNegative: false; QWordValue:    42949673);  // _0_01
 {$WARNINGS ON}
-{$ENDIF}
-
-{$IFNDEF FPC}
-type hwFloat = Extended;
-{$ENDIF}
 
 implementation
 uses uSinTable;
 
 
-{$IFDEF FPC}
-
 function int2hwFloat (const i: LongInt) : hwFloat; inline;
 begin
 int2hwFloat.isNegative:= i < 0;
@@ -221,7 +208,6 @@
     hwFloat2Float:= -hwFloat2Float;
 end;
 
-{$IFNDEF WEB}
 operator = (const z1, z2: hwFloat) z : boolean; inline;
 begin
     z:= (z1.isNegative = z2.isNegative) and (z1.QWordValue = z2.QWordValue);
@@ -274,7 +260,7 @@
     end
 end;
 
-function isZero(const z: hwFloat): boolean; inline; 
+function isZero(const z: hwFloat): boolean; inline;
 begin
 isZero := z.QWordValue = 0;
 end;
@@ -287,7 +273,7 @@
     if z1.QWordValue = z2.QWordValue then
         b:= false
     else
-        b:= not((z1.QWordValue = z2.QWordValue) or ((z2.QWordValue < z1.QWordValue) <> z1.isNegative))
+        b:= (z2.QWordValue < z1.QWordValue) = z1.isNegative
 end;
 
 operator > (const z1, z2: hwFloat) b : boolean; inline;
@@ -300,254 +286,183 @@
     else
         b:= (z1.QWordValue > z2.QWordValue) <> z2.isNegative
 end;
-{$ENDIF}
-{$IFDEF WEB}
-(*
-    Mostly to be kind to JS as of 2012-08-27 where there is no int64/uint64.  This may change though.
-*)
-operator = (const z1, z2: hwFloat) z : boolean; inline;
-begin
-    z:= (z1.isNegative = z2.isNegative) and (z1.Frac = z2.Frac) and (z1.Round = z2.Round);
-end;
-
-operator <> (const z1, z2: hwFloat) z : boolean; inline;
-begin
-    z:= (z1.isNegative <> z2.isNegative) or (z1.Frac <> z2.Frac) or (z1.Round <> z2.Round);
-end;
-
-operator + (const z1, z2: hwFloat) z : hwFloat; inline;
-begin
-if z1.isNegative = z2.isNegative then
-    begin
-    z:= z1;
-    z.Frac:= z.Frac + z2.Frac;
-    z.Round:= z.Round + z2.Round;
-    if z.Frac<z1.Frac then inc(z.Round)
-    end
-else
-    if (z1.Round > z2.Round) or ((z1.Round = z2.Round) and (z1.Frac > z2.Frac)) then
-        begin
-        z.isNegative:= z1.isNegative;
-        z.Round:= z1.Round - z2.Round;
-        z.Frac:= z1.Frac - z2.Frac;
-        if z2.Frac > z1.Frac then dec(z.Round)
-        end
-    else
-        begin
-        z.isNegative:= z2.isNegative;
-        z.Round:= z2.Round - z1.Round;
-        z.Frac:= z2.Frac-z1.Frac;
-        if z2.Frac < z1.Frac then dec(z.Round)
-        end
-end;
-
-operator - (const z1, z2: hwFloat) z : hwFloat; inline;
-begin
-if z1.isNegative = z2.isNegative then
-    if (z1.Round > z2.Round) or ((z1.Round = z2.Round) and (z1.Frac > z2.Frac)) then
-        begin
-        z.isNegative:= z1.isNegative;
-        z.Round:= z1.Round - z2.Round;
-        z.Frac:= z1.Frac-z2.Frac;
-        if z2.Frac > z1.Frac then dec(z.Round)
-        end
-    else
-        begin
-        z.isNegative:= not z2.isNegative;
-        z.Round:= z2.Round - z1.Round;
-        z.Frac:= z2.Frac-z1.Frac;
-        if z2.Frac < z1.Frac then dec(z.Round)
-        end
-else
-    begin
-    z:= z1;
-    z.Frac:= z.Frac + z2.Frac;
-    z.Round:= z.Round + z2.Round;
-    if z.Frac<z1.Frac then inc(z.Round)
-    end
-end;
-
-operator < (const z1, z2: hwFloat) b : boolean; inline;
-begin
-if z1.isNegative xor z2.isNegative then
-    b:= z1.isNegative
-else
-(*  Not so sure this specialcase is a win w/ Round/Frac. have to do more tests anyway.
-    if (z1.Round = z2.Round and (z1.Frac = z2.Frac)) then
-        b:= false
-    else *)
-        b:= ((z1.Round < z2.Round) or ((z1.Round = z2.Round) and (z1.Frac < z2.Frac))) <> z1.isNegative
-end;
-
-operator > (const z1, z2: hwFloat) b : boolean; inline;
-begin
-if z1.isNegative xor z2.isNegative then
-    b:= z2.isNegative
-else
-(*
-    if z1.QWordValue = z2.QWordValue then
-        b:= false
-    else*)
-        b:= ((z1.Round > z2.Round) or ((z1.Round = z2.Round) and (z1.Frac > z2.Frac))) <> z1.isNegative
-end;
-
-function isZero(const z: hwFloat): boolean; inline; 
-begin
-isZero := (z.Round = 0) and (z.Frac = 0);
-end;
-{$ENDIF}
 
 operator - (const z1: hwFloat) z : hwFloat; inline;
 begin
-z:= z1;
-z.isNegative:= not z.isNegative
+    z:= z1;
+    z.isNegative:= not z.isNegative
 end;
 
 
 operator * (const z1, z2: hwFloat) z : hwFloat; inline;
 begin
-z.isNegative:= z1.isNegative xor z2.isNegative;
-z.QWordValue:= QWord(z1.Round) * z2.Frac + QWord(z1.Frac) * z2.Round + ((QWord(z1.Frac) * z2.Frac) shr 32);
-z.Round:= z.Round + QWord(z1.Round) * z2.Round;
+    z.isNegative:= z1.isNegative xor z2.isNegative;
+    z.QWordValue:= QWord(z1.Round) * z2.Frac + QWord(z1.Frac) * z2.Round + ((QWord(z1.Frac) * z2.Frac) shr 32);
+    z.Round:= z.Round + QWord(z1.Round) * z2.Round;
 end;
 
 operator * (const z1: hwFloat; const z2: LongInt) z : hwFloat; inline;
 begin
-z.isNegative:= z1.isNegative xor (z2 < 0);
-z.QWordValue:= z1.QWordValue * abs(z2)
+    z.isNegative:= z1.isNegative xor (z2 < 0);
+    z.QWordValue:= z1.QWordValue * abs(z2)
 end;
 
 operator / (const z1: hwFloat; z2: hwFloat) z : hwFloat; inline;
-var t: hwFloat;
+var t: QWord;
 begin
-z.isNegative:= z1.isNegative xor z2.isNegative;
-z.Round:= z1.QWordValue div z2.QWordValue;
-t:= z1 - z2 * z.Round;
-if t.QWordValue = 0 then
-    z.Frac:= 0
-else
-    begin
-    while ((t.QWordValue and $8000000000000000) = 0) and ((z2.QWordValue and $8000000000000000) = 0) do
+    z.isNegative:= z1.isNegative xor z2.isNegative;
+    z.Round:= z1.QWordValue div z2.QWordValue;
+    t:= z1.QWordValue - z2.QWordValue * z.Round;
+    z.Frac:= 0;
+
+    if t <> 0 then
         begin
-        t.QWordValue:= t.QWordValue shl 1;
-        z2.QWordValue:= z2.QWordValue shl 1
-        end;
-    if z2.Round > 0 then
-        z.Frac:= (t.QWordValue) div (z2.Round)
-    else
-        z.Frac:= 0
-    end
+        while ((t and $FF00000000000000) = 0) and ((z2.QWordValue and $FF00000000000000) = 0) do
+            begin
+            t:= t shl 8;
+            z2.QWordValue:= z2.QWordValue shl 8
+            end;
+
+        if z2.Round > 0 then
+            inc(z.QWordValue, t div z2.Round);
+        end
 end;
 
 operator / (const z1: hwFloat; const z2: LongInt) z : hwFloat; inline;
 begin
-z.isNegative:= z1.isNegative xor (z2 < 0);
-z.QWordValue:= z1.QWordValue div abs(z2)
+    z.isNegative:= z1.isNegative xor (z2 < 0);
+    z.QWordValue:= z1.QWordValue div abs(z2)
 end;
 
 function cstr(const z: hwFloat): shortstring;
 var tmpstr: shortstring;
 begin
-str(z.Round, cstr);
-if z.Frac <> 0 then
-    begin
-    str(z.Frac / $100000000, tmpstr);
-    delete(tmpstr, 1, 2);
-    cstr:= cstr + '.' + copy(tmpstr, 1, 10)
-    end;
-if z.isNegative then
-    cstr:= '-' + cstr
+    str(z.Round, cstr);
+    if z.Frac <> 0 then
+        begin
+        str(z.Frac / $100000000, tmpstr);
+        delete(tmpstr, 1, 2);
+        cstr:= cstr + '.' + copy(tmpstr, 1, 10)
+        end;
+    if z.isNegative then
+        cstr:= '-' + cstr
 end;
 
 function hwRound(const t: hwFloat): LongInt;
 begin
-if t.isNegative then
-    hwRound:= -(t.Round and $7FFFFFFF)
-else
-    hwRound:= t.Round and $7FFFFFFF
+    if t.isNegative then
+        hwRound:= -(t.Round and $7FFFFFFF)
+    else
+        hwRound:= t.Round and $7FFFFFFF
 end;
 
 function hwAbs(const t: hwFloat): hwFloat;
 begin
-hwAbs:= t;
-hwAbs.isNegative:= false
+    hwAbs:= t;
+    hwAbs.isNegative:= false
 end;
 
 function hwSqr(const t: hwFloat): hwFloat; inline;
 begin
-hwSqr.isNegative:= false;
-hwSqr.QWordValue:= ((QWord(t.Round) * t.Round) shl 32) + QWord(t.Round) * t.Frac * 2 + ((QWord(t.Frac) * t.Frac) shr 32);
+    hwSqr.isNegative:= false;
+    hwSqr.QWordValue:= ((QWord(t.Round) * t.Round) shl 32) + QWord(t.Round) * t.Frac * 2 + ((QWord(t.Frac) * t.Frac) shr 32);
 end;
 
-function hwPow(const t: hwFloat;p: LongWord): hwFloat;
-begin
-hwPow:= t;
-if p mod 2 = 0 then hwPow.isNegative:= false;
-
-while p > 0 do
-    begin
-    hwPow.QWordValue:= QWord(hwPow.Round) * t.Frac + QWord(hwPow.Frac) * t.Round + ((QWord(hwPow.Frac) * t.Frac) shr 32);
-    dec(p)
-    end
-end;
-
-function hwSqrt(const t: hwFloat): hwFloat;
+function hwSqrt1(const t: hwFloat): hwFloat;
 const pwr = 8; // even value, feel free to adjust
-      rThreshold = 1 shl (pwr + 32);
-      lThreshold = 1 shl (pwr div 2 + 32);
+      rThreshold: QWord = 1 shl (pwr + 32);
+      lThreshold: QWord = 1 shl (pwr div 2 + 32);
 var l, r: QWord;
     c: hwFloat;
 begin
-hwSqrt.isNegative:= false;
+    hwSqrt1.isNegative:= false;
 
-if t.Round = 0 then
-    begin
-    l:= t.QWordValue;
-    r:= $100000000
-    end
-else
-    begin
-    if t.QWordValue > $FFFFFFFFFFFF then // t.Round > 65535.9999
+    if t.Round = 0 then
+        begin
+        l:= t.QWordValue;
+        r:= $100000000
+        end
+    else
         begin
-        l:= $10000000000; // 256
-        r:= $FFFFFFFFFFFF; // 65535.9999
-        end else
-        if t.QWordValue >= rThreshold then
+        if t.QWordValue > $FFFFFFFFFFFF then // t.Round > 65535.9999
             begin
-            l:= lThreshold;
-            r:= $10000000000; // 256
-            end else
-            begin
-            l:= $100000000;
-            r:= lThreshold;
-            end;
+            l:= $10000000000; // 256
+            r:= $FFFFFFFFFFFF; // 65535.9999
+            end
+        else
+            if t.QWordValue >= rThreshold then
+                begin
+                l:= lThreshold;
+                r:= $10000000000; // 256
+                end
+            else
+                begin
+                l:= $100000000;
+                r:= lThreshold;
+                end;
     end;
 
-repeat
-    c.QWordValue:= (l + r) shr 1;
-    if hwSqr(c).QWordValue > t.QWordValue then
-        r:= c.QWordValue
-    else
-        l:= c.QWordValue
-until r - l <= 1;
+    repeat
+        c.QWordValue:= (l + r) shr 1;
+        if hwSqr(c).QWordValue > t.QWordValue then
+            r:= c.QWordValue
+        else
+            l:= c.QWordValue
+    until r - l <= 1;
 
-hwSqrt.QWordValue:= l
+    hwSqrt1.QWordValue:= l
 end;
 
-function Distance(const dx, dy: hwFloat): hwFloat;
+function hwSqrt(const x: hwFloat): hwFloat;
+var r, t, s, q: QWord;
+    i: integer;
 begin
-Distance:= hwSqrt(hwSqr(dx) + hwSqr(dy))
+    hwSqrt.isNegative:= false;
+
+    t:= $4000000000000000;
+    r:= 0;
+    q:= x.QWordValue;
+
+    for i:= 0 to 31 do
+        begin
+        s:= r + t;
+        r:= r shr 1;
+        if s <= q then
+            begin
+            dec(q, s);
+            inc(r, t);
+            end;
+        t:= t shr 2;
+        end;
+
+    hwSqrt.QWordValue:= r shl 16
+end;
+
+
+
+function Distance(const dx, dy: hwFloat): hwFloat;
+var r: QWord;
+begin
+    r:= dx.QWordValue or dy.QWordValue;
+
+    if r < $10000 then
+        begin
+        Distance.QWordValue:= r;
+        Distance.isNegative:= false
+        end
+    else
+        Distance:= hwSqrt(hwSqr(dx) + hwSqr(dy))
 end;
 
 function DistanceI(const dx, dy: LongInt): hwFloat;
 begin
-DistanceI:= hwSqrt(int2hwFloat(sqr(dx) + sqr(dy)))
+    DistanceI:= hwSqrt(int2hwFloat(sqr(dx) + sqr(dy)))
 end;
 
 function SignAs(const num, signum: hwFloat): hwFloat;
 begin
-SignAs.QWordValue:= num.QWordValue;
-SignAs.isNegative:= signum.isNegative
+    SignAs.QWordValue:= num.QWordValue;
+    SignAs.isNegative:= signum.isNegative
 end;
 
 function hwSign(r: hwFloat): LongInt;
@@ -620,6 +535,4 @@
     vector2Angle:= c
 end;
 
-{$ENDIF}
-
 end.