hedgewars/uFloat.pas
branchhedgeroid
changeset 7855 ddcdedd3330b
parent 7715 8b653edac2a2
child 8026 4a4f21070479
child 8838 aa2ffd427f6a
equal deleted inserted replaced
6350:41b0a9955c47 7855:ddcdedd3330b
     1 (*
     1 (*
     2  * Hedgewars, a free turn based strategy game
     2  * Hedgewars, a free turn based strategy game
     3  * Copyright (c) 2004-2011 Andrey Korotaev <unC0Rr@gmail.com>
     3  * Copyright (c) 2004-2012 Andrey Korotaev <unC0Rr@gmail.com>
     4  *
     4  *
     5  * This program is free software; you can redistribute it and/or modify
     5  * This program is free software; you can redistribute it and/or modify
     6  * it under the terms of the GNU General Public License as published by
     6  * it under the terms of the GNU General Public License as published by
     7  * the Free Software Foundation; version 2 of the License
     7  * the Free Software Foundation; version 2 of the License
     8  *
     8  *
    40 interface
    40 interface
    41 
    41 
    42 {$IFDEF FPC}
    42 {$IFDEF FPC}
    43 {$IFDEF ENDIAN_LITTLE}
    43 {$IFDEF ENDIAN_LITTLE}
    44 type hwFloat = record
    44 type hwFloat = record
    45                isNegative: boolean;
    45     isNegative: boolean;
    46                case byte of
    46     case byte of
    47                0: (Frac, Round: Longword);
    47         0: (Frac, Round: Longword);
    48                1: (QWordValue : QWord);
    48         1: (QWordValue : QWord);
    49                end;
    49         end;
    50 {$ELSE}
    50 {$ELSE}
    51 type hwFloat = record
    51 type hwFloat = record
    52                isNegative: boolean;
    52     isNegative: boolean;
    53                case byte of
    53     case byte of
    54                0: (Round, Frac: Longword);
    54     0: (Round, Frac: Longword);
    55                1: (QWordValue : QWord);
    55     1: (QWordValue : QWord);
    56                end;
    56     end;
    57 {$ENDIF}
    57 {$ENDIF}
    58 
    58 
    59 // Returns an hwFloat that represents the value of integer parameter i
    59 // Returns an hwFloat that represents the value of integer parameter i
    60 function int2hwFloat (const i: LongInt) : hwFloat; inline;
    60 function int2hwFloat (const i: LongInt) : hwFloat; inline;
    61 function hwFloat2Float (const i: hwFloat) : extended; inline;
    61 function hwFloat2Float (const i: hwFloat) : extended; inline;
    62 
    62 
    63 // The implemented operators
    63 // The implemented operators
    64 
    64 
    65 operator = (const z1, z2: hwFloat) z:boolean; inline;
    65 operator = (const z1, z2: hwFloat) z : boolean; inline;
       
    66 {$IFDEF PAS2C}
       
    67 operator <> (const z1, z2: hwFloat) z : boolean; inline;
       
    68 {$ENDIF}
    66 operator + (const z1, z2: hwFloat) z : hwFloat; inline;
    69 operator + (const z1, z2: hwFloat) z : hwFloat; inline;
    67 operator - (const z1, z2: hwFloat) z : hwFloat; inline;
    70 operator - (const z1, z2: hwFloat) z : hwFloat; inline;
    68 operator - (const z1: hwFloat) z : hwFloat; inline;
    71 operator - (const z1: hwFloat) z : hwFloat; inline;
    69 
    72 
    70 operator * (const z1, z2: hwFloat) z : hwFloat; inline;
    73 operator * (const z1, z2: hwFloat) z : hwFloat; inline;
    80 
    83 
    81 function cstr(const z: hwFloat): shortstring; // Returns a shortstring representations of the hwFloat.
    84 function cstr(const z: hwFloat): shortstring; // Returns a shortstring representations of the hwFloat.
    82 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)
    85 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)
    83 function hwAbs(const t: hwFloat): hwFloat; inline; // Returns the value of t with positive sign.
    86 function hwAbs(const t: hwFloat): hwFloat; inline; // Returns the value of t with positive sign.
    84 function hwSqr(const t: hwFloat): hwFloat; inline; // Returns the square value of parameter t.
    87 function hwSqr(const t: hwFloat): hwFloat; inline; // Returns the square value of parameter t.
       
    88 function hwPow(const t: hwFloat; p: LongWord): hwFloat; inline; // Returns the power of the value
    85 function hwSqrt(const t: hwFloat): hwFloat; inline; // Returns the the positive square root of parameter t.
    89 function hwSqrt(const t: hwFloat): hwFloat; inline; // Returns the the positive square root of parameter t.
    86 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.
    90 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.
    87 function DistanceI(const dx, dy: LongInt): hwFloat; // Same as above for integer parameters.
    91 function DistanceI(const dx, dy: LongInt): hwFloat; // Same as above for integer parameters.
    88 function AngleSin(const Angle: Longword): hwFloat;
    92 function AngleSin(const Angle: Longword): hwFloat;
    89 function AngleCos(const Angle: Longword): hwFloat;
    93 function AngleCos(const Angle: Longword): hwFloat;
       
    94 function vector2Angle(const x, y: hwFloat): LongInt;
    90 function SignAs(const num, signum: hwFloat): hwFloat; inline; // Returns an hwFloat with the value of parameter num and the sign of signum.
    95 function SignAs(const num, signum: hwFloat): hwFloat; inline; // Returns an hwFloat with the value of parameter num and the sign of signum.
    91 function hwSign(r: hwFloat): LongInt; inline; // Returns an integer with value 1 and sign of parameter r.
    96 function hwSign(r: hwFloat): LongInt; inline; // Returns an integer with value 1 and sign of parameter r.
       
    97 function hwSignf(r: real): LongInt; inline; // Returns an integer with value 1 and sign of parameter r.
    92 function isZero(const z: hwFloat): boolean; inline;
    98 function isZero(const z: hwFloat): boolean; inline;
    93 {$IFDEF FPC}
    99 {$IFDEF FPC}
    94 {$J-}
   100 {$J-}
    95 {$ENDIF}
   101 {$ENDIF}
    96 {$WARNINGS OFF}
   102 {$WARNINGS OFF}
   108        _0_000064: hwFloat = (isNegative: false; QWordValue:      274878);
   114        _0_000064: hwFloat = (isNegative: false; QWordValue:      274878);
   109          _0_0002: hwFloat = (isNegative: false; QWordValue:      858993);
   115          _0_0002: hwFloat = (isNegative: false; QWordValue:      858993);
   110          _0_0005: hwFloat = (isNegative: false; QWordValue:     2147484);
   116          _0_0005: hwFloat = (isNegative: false; QWordValue:     2147484);
   111           _0_001: hwFloat = (isNegative: false; QWordValue:     4294967);
   117           _0_001: hwFloat = (isNegative: false; QWordValue:     4294967);
   112           _0_003: hwFloat = (isNegative: false; QWordValue:    12884902);
   118           _0_003: hwFloat = (isNegative: false; QWordValue:    12884902);
       
   119          _0_0032: hwFloat = (isNegative: false; QWordValue:    13743895);
   113           _0_004: hwFloat = (isNegative: false; QWordValue:    17179869);
   120           _0_004: hwFloat = (isNegative: false; QWordValue:    17179869);
   114           _0_005: hwFloat = (isNegative: false; QWordValue:    21474836);
   121           _0_005: hwFloat = (isNegative: false; QWordValue:    21474836);
   115           _0_008: hwFloat = (isNegative: false; QWordValue:    34359738);
   122           _0_008: hwFloat = (isNegative: false; QWordValue:    34359738);
   116            _0_01: hwFloat = (isNegative: false; QWordValue:    42949673);
   123            _0_01: hwFloat = (isNegative: false; QWordValue:    42949673);
       
   124          _0_0128: hwFloat = (isNegative: false; QWordValue:    54975581);
   117            _0_02: hwFloat = (isNegative: false; QWordValue:    85899345);
   125            _0_02: hwFloat = (isNegative: false; QWordValue:    85899345);
   118            _0_03: hwFloat = (isNegative: false; QWordValue:   128849018);
   126            _0_03: hwFloat = (isNegative: false; QWordValue:   128849018);
   119            _0_07: hwFloat = (isNegative: false; QWordValue:   300647710);
   127            _0_07: hwFloat = (isNegative: false; QWordValue:   300647710);
   120            _0_08: hwFloat = (isNegative: false; QWordValue:   343597383);
   128            _0_08: hwFloat = (isNegative: false; QWordValue:   343597383);
   121             _0_1: hwFloat = (isNegative: false; QWordValue:   429496730);
   129             _0_1: hwFloat = (isNegative: false; QWordValue:   429496730);
   141            _0_96: hwFloat = (isNegative: false; QWordValue:  4123168604);
   149            _0_96: hwFloat = (isNegative: false; QWordValue:  4123168604);
   142           _0_995: hwFloat = (isNegative: false; QWordValue:  4273492459);
   150           _0_995: hwFloat = (isNegative: false; QWordValue:  4273492459);
   143           _0_999: hwFloat = (isNegative: false; QWordValue:  4290672328);
   151           _0_999: hwFloat = (isNegative: false; QWordValue:  4290672328);
   144               _0: hwFloat = (isNegative: false; QWordValue:           0);
   152               _0: hwFloat = (isNegative: false; QWordValue:           0);
   145               _1: hwFloat = (isNegative: false; QWordValue:  4294967296);
   153               _1: hwFloat = (isNegative: false; QWordValue:  4294967296);
       
   154             _1_2: hwFloat = (isNegative: false; QWordValue:  1288490189*4);
   146             _1_5: hwFloat = (isNegative: false; QWordValue:  4294967296 * 3 div 2);
   155             _1_5: hwFloat = (isNegative: false; QWordValue:  4294967296 * 3 div 2);
       
   156             _1_6: hwFloat = (isNegative: false; QWordValue:  4294967296 * 8 div 5);
   147             _1_9: hwFloat = (isNegative: false; QWordValue:  8160437862);
   157             _1_9: hwFloat = (isNegative: false; QWordValue:  8160437862);
   148               _2: hwFloat = (isNegative: false; QWordValue:  4294967296 * 2);
   158               _2: hwFloat = (isNegative: false; QWordValue:  4294967296 * 2);
       
   159             _2_4: hwFloat = (isNegative: false; QWordValue:  4294967296 * 12 div 5);
   149               _3: hwFloat = (isNegative: false; QWordValue:  4294967296 * 3);
   160               _3: hwFloat = (isNegative: false; QWordValue:  4294967296 * 3);
       
   161             _3_2: hwFloat = (isNegative: false; QWordValue:  3435973837*4);
       
   162              _PI: hwFloat = (isNegative: false; QWordValue: 13493037704);
   150               _4: hwFloat = (isNegative: false; QWordValue:  4294967296 * 4);
   163               _4: hwFloat = (isNegative: false; QWordValue:  4294967296 * 4);
       
   164             _4_5: hwFloat = (isNegative: false; QWordValue:  4294967296 * 9 div 2);
   151               _5: hwFloat = (isNegative: false; QWordValue:  4294967296 * 5);
   165               _5: hwFloat = (isNegative: false; QWordValue:  4294967296 * 5);
   152               _6: hwFloat = (isNegative: false; QWordValue:  4294967296 * 6);
   166               _6: hwFloat = (isNegative: false; QWordValue:  4294967296 * 6);
       
   167             _6_4: hwFloat = (isNegative: false; QWordValue:  3435973837 * 8);
       
   168               _7: hwFloat = (isNegative: false; QWordValue:  4294967296 * 7);
   153              _10: hwFloat = (isNegative: false; QWordValue:  4294967296 * 10);
   169              _10: hwFloat = (isNegative: false; QWordValue:  4294967296 * 10);
   154              _12: hwFloat = (isNegative: false; QWordValue:  4294967296 * 12);
   170              _12: hwFloat = (isNegative: false; QWordValue:  4294967296 * 12);
   155              _16: hwFloat = (isNegative: false; QWordValue:  4294967296 * 16);
   171              _16: hwFloat = (isNegative: false; QWordValue:  4294967296 * 16);
   156              _19: hwFloat = (isNegative: false; QWordValue:  4294967296 * 19);
   172              _19: hwFloat = (isNegative: false; QWordValue:  4294967296 * 19);
   157              _20: hwFloat = (isNegative: false; QWordValue:  4294967296 * 20);
   173              _20: hwFloat = (isNegative: false; QWordValue:  4294967296 * 20);
   158              _25: hwFloat = (isNegative: false; QWordValue:  4294967296 * 25);
   174              _25: hwFloat = (isNegative: false; QWordValue:  4294967296 * 25);
   159              _30: hwFloat = (isNegative: false; QWordValue:  4294967296 * 30);
   175              _30: hwFloat = (isNegative: false; QWordValue:  4294967296 * 30);
   160              _40: hwFloat = (isNegative: false; QWordValue:  4294967296 * 40);
   176              _40: hwFloat = (isNegative: false; QWordValue:  4294967296 * 40);
       
   177              _41: hwFloat = (isNegative: false; QWordValue:  4294967296 * 41);
       
   178              _49: hwFloat = (isNegative: false; QWordValue:  4294967296 * 49);
   161              _50: hwFloat = (isNegative: false; QWordValue:  4294967296 * 50);
   179              _50: hwFloat = (isNegative: false; QWordValue:  4294967296 * 50);
   162              _70: hwFloat = (isNegative: false; QWordValue:  4294967296 * 70);
   180              _70: hwFloat = (isNegative: false; QWordValue:  4294967296 * 70);
   163              _90: hwFloat = (isNegative: false; QWordValue:  4294967296 * 90);
   181              _90: hwFloat = (isNegative: false; QWordValue:  4294967296 * 90);
   164             _128: hwFloat = (isNegative: false; QWordValue:  4294967296 * 128);
   182             _128: hwFloat = (isNegative: false; QWordValue:  4294967296 * 128);
   165             _180: hwFloat = (isNegative: false; QWordValue:  4294967296 * 180);
   183             _180: hwFloat = (isNegative: false; QWordValue:  4294967296 * 180);
   187 uses uSinTable;
   205 uses uSinTable;
   188 
   206 
   189 
   207 
   190 {$IFDEF FPC}
   208 {$IFDEF FPC}
   191 
   209 
   192 function int2hwFloat (const i: LongInt) : hwFloat;
   210 function int2hwFloat (const i: LongInt) : hwFloat; inline;
   193 begin
   211 begin
   194 int2hwFloat.isNegative:= i < 0;
   212 int2hwFloat.isNegative:= i < 0;
   195 int2hwFloat.Round:= abs(i);
   213 int2hwFloat.Round:= abs(i);
   196 int2hwFloat.Frac:= 0
   214 int2hwFloat.Frac:= 0
   197 end;
   215 end;
   198 
   216 
   199 function hwFloat2Float (const i: hwFloat) : extended;
   217 function hwFloat2Float (const i: hwFloat) : extended; inline;
   200 begin
   218 begin
   201 hwFloat2Float:= i.QWordValue / $100000000;
   219 hwFloat2Float:= i.Frac / $100000000 + i.Round;
   202 if i.isNegative then hwFloat2Float:= -hwFloat2Float;
   220 if i.isNegative then
   203 end;
   221     hwFloat2Float:= -hwFloat2Float;
   204 
   222 end;
   205 operator = (const z1, z2: hwFloat) z:boolean; inline;
   223 
       
   224 {$IFNDEF WEB}
       
   225 operator = (const z1, z2: hwFloat) z : boolean; inline;
   206 begin
   226 begin
   207     z:= (z1.isNegative = z2.isNegative) and (z1.QWordValue = z2.QWordValue);
   227     z:= (z1.isNegative = z2.isNegative) and (z1.QWordValue = z2.QWordValue);
   208 end;
   228 end;
   209 
   229 
   210 
   230 {$IFDEF PAS2C}
   211 operator + (const z1, z2: hwFloat) z : hwFloat;
   231 operator <> (const z1, z2: hwFloat) z : boolean; inline;
       
   232 begin
       
   233     z:= (z1.isNegative <> z2.isNegative) or (z1.QWordValue <> z2.QWordValue);
       
   234 end;
       
   235 {$ENDIF}
       
   236 
       
   237 operator + (const z1, z2: hwFloat) z : hwFloat; inline;
   212 begin
   238 begin
   213 if z1.isNegative = z2.isNegative then
   239 if z1.isNegative = z2.isNegative then
   214    begin
   240     begin
   215    z.isNegative:= z1.isNegative;
   241     z.isNegative:= z1.isNegative;
   216    z.QWordValue:= z1.QWordValue + z2.QWordValue
   242     z.QWordValue:= z1.QWordValue + z2.QWordValue
   217    end
   243     end
   218 else
   244 else
   219    if z1.QWordValue > z2.QWordValue then
   245     if z1.QWordValue > z2.QWordValue then
   220       begin
   246         begin
   221       z.isNegative:= z1.isNegative;
   247         z.isNegative:= z1.isNegative;
   222       z.QWordValue:= z1.QWordValue - z2.QWordValue
   248         z.QWordValue:= z1.QWordValue - z2.QWordValue
   223       end else
   249         end
   224       begin
   250     else
   225       z.isNegative:= z2.isNegative;
   251         begin
   226       z.QWordValue:= z2.QWordValue - z1.QWordValue
   252         z.isNegative:= z2.isNegative;
   227       end
   253         z.QWordValue:= z2.QWordValue - z1.QWordValue
   228 end;
   254         end
   229 
   255 end;
   230 operator - (const z1, z2: hwFloat) z : hwFloat;
   256 
       
   257 operator - (const z1, z2: hwFloat) z : hwFloat; inline;
   231 begin
   258 begin
   232 if z1.isNegative = z2.isNegative then
   259 if z1.isNegative = z2.isNegative then
   233    if z1.QWordValue > z2.QWordValue then
   260     if z1.QWordValue > z2.QWordValue then
   234       begin
   261         begin
   235       z.isNegative:= z1.isNegative;
   262         z.isNegative:= z1.isNegative;
   236       z.QWordValue:= z1.QWordValue - z2.QWordValue
   263         z.QWordValue:= z1.QWordValue - z2.QWordValue
   237       end else
   264         end
   238       begin
   265     else
   239       z.isNegative:= not z2.isNegative;
   266         begin
   240       z.QWordValue:= z2.QWordValue - z1.QWordValue
   267         z.isNegative:= not z2.isNegative;
   241       end
   268         z.QWordValue:= z2.QWordValue - z1.QWordValue
   242 else begin
   269         end
   243      z.isNegative:= z1.isNegative;
   270 else
   244      z.QWordValue:= z1.QWordValue + z2.QWordValue
   271     begin
   245      end
   272     z.isNegative:= z1.isNegative;
   246 end;
   273     z.QWordValue:= z1.QWordValue + z2.QWordValue
   247 
   274     end
   248 operator - (const z1: hwFloat) z : hwFloat;
   275 end;
       
   276 
       
   277 function isZero(const z: hwFloat): boolean; inline; 
       
   278 begin
       
   279 isZero := z.QWordValue = 0;
       
   280 end;
       
   281 
       
   282 operator < (const z1, z2: hwFloat) b : boolean; inline;
       
   283 begin
       
   284 if z1.isNegative xor z2.isNegative then
       
   285     b:= z1.isNegative
       
   286 else
       
   287     if z1.QWordValue = z2.QWordValue then
       
   288         b:= false
       
   289     else
       
   290         b:= not((z1.QWordValue = z2.QWordValue) or ((z2.QWordValue < z1.QWordValue) <> z1.isNegative))
       
   291 end;
       
   292 
       
   293 operator > (const z1, z2: hwFloat) b : boolean; inline;
       
   294 begin
       
   295 if z1.isNegative xor z2.isNegative then
       
   296     b:= z2.isNegative
       
   297 else
       
   298     if z1.QWordValue = z2.QWordValue then
       
   299         b:= false
       
   300     else
       
   301         b:= (z1.QWordValue > z2.QWordValue) <> z2.isNegative
       
   302 end;
       
   303 {$ENDIF}
       
   304 {$IFDEF WEB}
       
   305 (*
       
   306     Mostly to be kind to JS as of 2012-08-27 where there is no int64/uint64.  This may change though.
       
   307 *)
       
   308 operator = (const z1, z2: hwFloat) z : boolean; inline;
       
   309 begin
       
   310     z:= (z1.isNegative = z2.isNegative) and (z1.Frac = z2.Frac) and (z1.Round = z2.Round);
       
   311 end;
       
   312 
       
   313 operator <> (const z1, z2: hwFloat) z : boolean; inline;
       
   314 begin
       
   315     z:= (z1.isNegative <> z2.isNegative) or (z1.Frac <> z2.Frac) or (z1.Round <> z2.Round);
       
   316 end;
       
   317 
       
   318 operator + (const z1, z2: hwFloat) z : hwFloat; inline;
       
   319 begin
       
   320 if z1.isNegative = z2.isNegative then
       
   321     begin
       
   322     z:= z1;
       
   323     z.Frac:= z.Frac + z2.Frac;
       
   324     z.Round:= z.Round + z2.Round;
       
   325     if z.Frac<z1.Frac then inc(z.Round)
       
   326     end
       
   327 else
       
   328     if (z1.Round > z2.Round) or ((z1.Round = z2.Round) and (z1.Frac > z2.Frac)) then
       
   329         begin
       
   330         z.isNegative:= z1.isNegative;
       
   331         z.Round:= z1.Round - z2.Round;
       
   332         z.Frac:= z1.Frac - z2.Frac;
       
   333         if z2.Frac > z1.Frac then dec(z.Round)
       
   334         end
       
   335     else
       
   336         begin
       
   337         z.isNegative:= z2.isNegative;
       
   338         z.Round:= z2.Round - z1.Round;
       
   339         z.Frac:= z2.Frac-z1.Frac;
       
   340         if z2.Frac < z1.Frac then dec(z.Round)
       
   341         end
       
   342 end;
       
   343 
       
   344 operator - (const z1, z2: hwFloat) z : hwFloat; inline;
       
   345 begin
       
   346 if z1.isNegative = z2.isNegative then
       
   347     if (z1.Round > z2.Round) or ((z1.Round = z2.Round) and (z1.Frac > z2.Frac)) then
       
   348         begin
       
   349         z.isNegative:= z1.isNegative;
       
   350         z.Round:= z1.Round - z2.Round;
       
   351         z.Frac:= z1.Frac-z2.Frac;
       
   352         if z2.Frac > z1.Frac then dec(z.Round)
       
   353         end
       
   354     else
       
   355         begin
       
   356         z.isNegative:= not z2.isNegative;
       
   357         z.Round:= z2.Round - z1.Round;
       
   358         z.Frac:= z2.Frac-z1.Frac;
       
   359         if z2.Frac < z1.Frac then dec(z.Round)
       
   360         end
       
   361 else
       
   362     begin
       
   363     z:= z1;
       
   364     z.Frac:= z.Frac + z2.Frac;
       
   365     z.Round:= z.Round + z2.Round;
       
   366     if z.Frac<z1.Frac then inc(z.Round)
       
   367     end
       
   368 end;
       
   369 
       
   370 operator < (const z1, z2: hwFloat) b : boolean; inline;
       
   371 begin
       
   372 if z1.isNegative xor z2.isNegative then
       
   373     b:= z1.isNegative
       
   374 else
       
   375 (*  Not so sure this specialcase is a win w/ Round/Frac. have to do more tests anyway.
       
   376     if (z1.Round = z2.Round and (z1.Frac = z2.Frac)) then
       
   377         b:= false
       
   378     else *)
       
   379         b:= ((z1.Round < z2.Round) or ((z1.Round = z2.Round) and (z1.Frac < z2.Frac))) <> z1.isNegative
       
   380 end;
       
   381 
       
   382 operator > (const z1, z2: hwFloat) b : boolean; inline;
       
   383 begin
       
   384 if z1.isNegative xor z2.isNegative then
       
   385     b:= z2.isNegative
       
   386 else
       
   387 (*
       
   388     if z1.QWordValue = z2.QWordValue then
       
   389         b:= false
       
   390     else*)
       
   391         b:= ((z1.Round > z2.Round) or ((z1.Round = z2.Round) and (z1.Frac > z2.Frac))) <> z1.isNegative
       
   392 end;
       
   393 
       
   394 function isZero(const z: hwFloat): boolean; inline; 
       
   395 begin
       
   396 isZero := (z.Round = 0) and (z.Frac = 0);
       
   397 end;
       
   398 {$ENDIF}
       
   399 
       
   400 operator - (const z1: hwFloat) z : hwFloat; inline;
   249 begin
   401 begin
   250 z:= z1;
   402 z:= z1;
   251 z.isNegative:= not z.isNegative
   403 z.isNegative:= not z.isNegative
   252 end;
   404 end;
   253 
   405 
   254 
   406 
   255 operator * (const z1, z2: hwFloat) z : hwFloat;
   407 operator * (const z1, z2: hwFloat) z : hwFloat; inline;
   256 begin
   408 begin
   257 z.isNegative:= z1.isNegative xor z2.isNegative;
   409 z.isNegative:= z1.isNegative xor z2.isNegative;
   258 z.QWordValue:= QWord(z1.Round) * z2.Frac +
   410 z.QWordValue:= QWord(z1.Round) * z2.Frac + QWord(z1.Frac) * z2.Round + ((QWord(z1.Frac) * z2.Frac) shr 32);
   259                QWord(z1.Frac) * z2.Round +
       
   260                ((QWord(z1.Frac) * z2.Frac) shr 32);
       
   261 z.Round:= z.Round + QWord(z1.Round) * z2.Round;
   411 z.Round:= z.Round + QWord(z1.Round) * z2.Round;
   262 end;
   412 end;
   263 
   413 
   264 operator * (const z1: hwFloat; const z2: LongInt) z : hwFloat;
   414 operator * (const z1: hwFloat; const z2: LongInt) z : hwFloat; inline;
   265 begin
   415 begin
   266 z.isNegative:= z1.isNegative xor (z2 < 0);
   416 z.isNegative:= z1.isNegative xor (z2 < 0);
   267 z.QWordValue:= z1.QWordValue * abs(z2)
   417 z.QWordValue:= z1.QWordValue * abs(z2)
   268 end;
   418 end;
   269 
   419 
   270 operator / (const z1: hwFloat; z2: hwFloat) z : hwFloat;
   420 operator / (const z1: hwFloat; z2: hwFloat) z : hwFloat; inline;
   271 var t: hwFloat;
   421 var t: hwFloat;
   272 begin
   422 begin
   273 z.isNegative:= z1.isNegative xor z2.isNegative;
   423 z.isNegative:= z1.isNegative xor z2.isNegative;
   274 z.Round:= z1.QWordValue div z2.QWordValue;
   424 z.Round:= z1.QWordValue div z2.QWordValue;
   275 t:= z1 - z2 * z.Round;
   425 t:= z1 - z2 * z.Round;
   276 if t.QWordValue = 0 then
   426 if t.QWordValue = 0 then
   277    z.Frac:= 0
   427     z.Frac:= 0
   278 else
   428 else
   279    begin
   429     begin
   280    while ((t.QWordValue and $8000000000000000) = 0) and
   430     while ((t.QWordValue and $8000000000000000) = 0) and ((z2.QWordValue and $8000000000000000) = 0) do
   281          ((z2.QWordValue and $8000000000000000) = 0) do
   431         begin
   282          begin
   432         t.QWordValue:= t.QWordValue shl 1;
   283          t.QWordValue:= t.QWordValue shl 1;
   433         z2.QWordValue:= z2.QWordValue shl 1
   284          z2.QWordValue:= z2.QWordValue shl 1
   434         end;
   285          end;
   435     if z2.Round > 0 then
   286    if z2.Round > 0 then z.Frac:= (t.QWordValue) div (z2.Round)
   436         z.Frac:= (t.QWordValue) div (z2.Round)
   287                    else z.Frac:= 0
   437     else
   288    end
   438         z.Frac:= 0
   289 end;
   439     end
   290 
   440 end;
   291 operator / (const z1: hwFloat; const z2: LongInt) z : hwFloat;
   441 
       
   442 operator / (const z1: hwFloat; const z2: LongInt) z : hwFloat; inline;
   292 begin
   443 begin
   293 z.isNegative:= z1.isNegative xor (z2 < 0);
   444 z.isNegative:= z1.isNegative xor (z2 < 0);
   294 z.QWordValue:= z1.QWordValue div abs(z2)
   445 z.QWordValue:= z1.QWordValue div abs(z2)
   295 end;
   446 end;
   296 
   447 
   297 operator < (const z1, z2: hwFloat) b : boolean;
       
   298 begin
       
   299 if z1.isNegative xor z2.isNegative then
       
   300    b:= z1.isNegative
       
   301 else
       
   302    if z1.QWordValue = z2.QWordValue then
       
   303       b:= false
       
   304    else
       
   305       b:= (z1.QWordValue < z2.QWordValue) xor z1.isNegative
       
   306 end;
       
   307 
       
   308 operator > (const z1, z2: hwFloat) b : boolean;
       
   309 begin
       
   310 if z1.isNegative xor z2.isNegative then
       
   311    b:= z2.isNegative
       
   312 else
       
   313    if z1.QWordValue = z2.QWordValue then
       
   314       b:= false
       
   315    else
       
   316       b:= (z1.QWordValue > z2.QWordValue) xor z2.isNegative
       
   317 end;
       
   318 
       
   319 function cstr(const z: hwFloat): shortstring;
   448 function cstr(const z: hwFloat): shortstring;
   320 var tmpstr: shortstring;
   449 var tmpstr: shortstring;
   321 begin
   450 begin
   322 str(z.Round, cstr);
   451 str(z.Round, cstr);
   323 if z.Frac <> 0 then
   452 if z.Frac <> 0 then
   324    begin
   453     begin
   325    str(z.Frac / $100000000:1:10, tmpstr);
   454     str(z.Frac / $100000000, tmpstr);
   326    delete(tmpstr, 1, 2);
   455     delete(tmpstr, 1, 2);
   327    cstr:= cstr + '.' + tmpstr
   456     cstr:= cstr + '.' + copy(tmpstr, 1, 10)
   328    end;
   457     end;
   329 if z.isNegative then cstr:= '-' + cstr
   458 if z.isNegative then
       
   459     cstr:= '-' + cstr
   330 end;
   460 end;
   331 
   461 
   332 function hwRound(const t: hwFloat): LongInt;
   462 function hwRound(const t: hwFloat): LongInt;
   333 begin
   463 begin
   334 if t.isNegative then hwRound:= -(t.Round and $7FFFFFFF)
   464 if t.isNegative then
   335                 else hwRound:= t.Round and $7FFFFFFF
   465     hwRound:= -(t.Round and $7FFFFFFF)
       
   466 else
       
   467     hwRound:= t.Round and $7FFFFFFF
   336 end;
   468 end;
   337 
   469 
   338 function hwAbs(const t: hwFloat): hwFloat;
   470 function hwAbs(const t: hwFloat): hwFloat;
   339 begin
   471 begin
   340 hwAbs:= t;
   472 hwAbs:= t;
   341 hwAbs.isNegative:= false
   473 hwAbs.isNegative:= false
   342 end;
   474 end;
   343 
   475 
   344 function hwSqr(const t: hwFloat): hwFloat;
   476 function hwSqr(const t: hwFloat): hwFloat; inline;
   345 begin
   477 begin
   346 hwSqr.isNegative:= false;
   478 hwSqr.isNegative:= false;
   347 hwSqr.QWordValue:=
   479 hwSqr.QWordValue:= ((QWord(t.Round) * t.Round) shl 32) + QWord(t.Round) * t.Frac * 2 + ((QWord(t.Frac) * t.Frac) shr 32);
   348       ((QWord(t.Round) * t.Round) shl 32)
   480 end;
   349     + QWord(t.Round) * t.Frac * 2
   481 
   350     + ((QWord(t.Frac) * t.Frac) shr 32);
   482 function hwPow(const t: hwFloat;p: LongWord): hwFloat;
       
   483 begin
       
   484 hwPow:= t;
       
   485 if p mod 2 = 0 then hwPow.isNegative:= false;
       
   486 
       
   487 while p > 0 do
       
   488     begin
       
   489     hwPow.QWordValue:= QWord(hwPow.Round) * t.Frac + QWord(hwPow.Frac) * t.Round + ((QWord(hwPow.Frac) * t.Frac) shr 32);
       
   490     dec(p)
       
   491     end
   351 end;
   492 end;
   352 
   493 
   353 function hwSqrt(const t: hwFloat): hwFloat;
   494 function hwSqrt(const t: hwFloat): hwFloat;
       
   495 const pwr = 8; // even value, feel free to adjust
       
   496       rThreshold = 1 shl (pwr + 32);
       
   497       lThreshold = 1 shl (pwr div 2 + 32);
   354 var l, r: QWord;
   498 var l, r: QWord;
   355     c: hwFloat;
   499     c: hwFloat;
   356 begin
   500 begin
   357 hwSqrt.isNegative:= false;
   501 hwSqrt.isNegative:= false;
   358 
   502 
   359 if t.Round = 0 then
   503 if t.Round = 0 then
   360    begin
   504     begin
   361    l:= t.QWordValue;
   505     l:= t.QWordValue;
   362    r:= $100000000
   506     r:= $100000000
   363    end else
   507     end
   364    begin
   508 else
   365    l:= $100000000;
   509     begin
   366    r:= t.QWordValue div 2 + $80000000; // r:= t / 2 + 0.5
   510     if t.QWordValue > $FFFFFFFFFFFF then // t.Round > 65535.9999
   367    if r > $FFFFFFFFFFFF then r:= $FFFFFFFFFFFF
   511         begin
   368    end;
   512         l:= $10000000000; // 256
       
   513         r:= $FFFFFFFFFFFF; // 65535.9999
       
   514         end else
       
   515         if t.QWordValue >= rThreshold then
       
   516             begin
       
   517             l:= lThreshold;
       
   518             r:= $10000000000; // 256
       
   519             end else
       
   520             begin
       
   521             l:= $100000000;
       
   522             r:= lThreshold;
       
   523             end;
       
   524     end;
   369 
   525 
   370 repeat
   526 repeat
   371   c.QWordValue:= (l + r) div 2;
   527     c.QWordValue:= (l + r) shr 1;
   372   if hwSqr(c).QWordValue > t.QWordValue then r:= c.QWordValue else l:= c.QWordValue
   528     if hwSqr(c).QWordValue > t.QWordValue then
       
   529         r:= c.QWordValue
       
   530     else
       
   531         l:= c.QWordValue
   373 until r - l <= 1;
   532 until r - l <= 1;
   374 
   533 
   375 hwSqrt.QWordValue:= l
   534 hwSqrt.QWordValue:= l
   376 end;
   535 end;
   377 
   536 
   392 end;
   551 end;
   393 
   552 
   394 function hwSign(r: hwFloat): LongInt;
   553 function hwSign(r: hwFloat): LongInt;
   395 begin
   554 begin
   396 // yes, we have negative zero for a reason
   555 // yes, we have negative zero for a reason
   397 if r.isNegative then hwSign:= -1 else hwSign:= 1
   556 if r.isNegative then
       
   557     hwSign:= -1
       
   558 else
       
   559     hwSign:= 1
       
   560 end;
       
   561 
       
   562 function hwSignf(r: real): LongInt;
       
   563 begin
       
   564 if r < 0 then
       
   565     hwSignf:= -1
       
   566 else
       
   567     hwSignf:= 1
   398 end;
   568 end;
   399 
   569 
   400 
   570 
   401 function AngleSin(const Angle: Longword): hwFloat;
   571 function AngleSin(const Angle: Longword): hwFloat;
   402 begin
   572 begin
   403 //TryDo((Angle >= 0) and (Angle <= 2048), 'Sin param exceeds limits', true);
   573 //TryDo((Angle >= 0) and (Angle <= 2048), 'Sin param exceeds limits', true);
   404 AngleSin.isNegative:= false;
   574 AngleSin.isNegative:= false;
   405 if Angle < 1024 then AngleSin.QWordValue:= SinTable[Angle]
   575 if Angle < 1024 then
   406                 else AngleSin.QWordValue:= SinTable[2048 - Angle]
   576     AngleSin.QWordValue:= SinTable[Angle]
       
   577 else
       
   578     AngleSin.QWordValue:= SinTable[2048 - Angle]
   407 end;
   579 end;
   408 
   580 
   409 function AngleCos(const Angle: Longword): hwFloat;
   581 function AngleCos(const Angle: Longword): hwFloat;
   410 begin
   582 begin
   411 //TryDo((Angle >= 0) and (Angle <= 2048), 'Cos param exceeds limits', true);
   583 //TryDo((Angle >= 0) and (Angle <= 2048), 'Cos param exceeds limits', true);
   412 AngleCos.isNegative:= Angle > 1024;
   584 AngleCos.isNegative:= Angle > 1024;
   413 if Angle < 1024 then AngleCos.QWordValue:= SinTable[1024 - Angle]
   585 if Angle < 1024 then
   414                 else AngleCos.QWordValue:= SinTable[Angle - 1024]
   586     AngleCos.QWordValue:= SinTable[1024 - Angle]
   415 end;
   587 else
   416 
   588     AngleCos.QWordValue:= SinTable[Angle - 1024]
   417 function isZero(const z: hwFloat): boolean; inline; 
   589 end;
   418 begin
   590 
   419     isZero := z.QWordValue = 0;
   591 function vector2Angle(const x, y: hwFloat): LongInt;
   420 end;
   592 var d, nf: hwFloat;
       
   593     l, r, c, oc: Longword;
       
   594     n: QWord;
       
   595 begin
       
   596     d:= _1 / Distance(x, y);
       
   597 
       
   598     nf:= y * d;
       
   599     n:= nf.QWordValue;
       
   600 
       
   601     l:= 0;
       
   602     r:= 1024;
       
   603     c:= 0;
       
   604 
       
   605     repeat
       
   606         oc:= c;
       
   607 
       
   608         c:= (l + r) shr 1;
       
   609 
       
   610         if n >= SinTable[c] then
       
   611             l:= c
       
   612         else
       
   613             r:= c;
       
   614 
       
   615     until (oc = c);
       
   616 
       
   617     if x.isNegative then c:= 2048 - c;
       
   618     if y.isNegative then c:= - c;
       
   619 
       
   620     vector2Angle:= c
       
   621 end;
       
   622 
   421 {$ENDIF}
   623 {$ENDIF}
   422 
   624 
   423 end.
   625 end.