hedgewars/uFloat.pas
changeset 10015 4feced261c68
parent 9998 736015b847e3
parent 9970 88353250ad7d
child 10108 c68cf030eded
equal deleted inserted replaced
10014:56d2f2d5aad8 10015:4feced261c68
    37  *       Use and extend the list if needed, rather than using int2hwFloat()
    37  *       Use and extend the list if needed, rather than using int2hwFloat()
    38  *       with integer constants.
    38  *       with integer constants.
    39  *)
    39  *)
    40 interface
    40 interface
    41 
    41 
    42 {$IFDEF FPC}
       
    43 {$IFDEF ENDIAN_LITTLE}
    42 {$IFDEF ENDIAN_LITTLE}
    44 type hwFloat = record
    43 type hwFloat = record
    45     isNegative: boolean;
    44     isNegative: boolean;
    46     case byte of
    45     case byte of
    47         0: (Frac, Round: Longword);
    46         0: (Frac, Round: Longword);
    61 function hwFloat2Float (const i: hwFloat) : extended; inline;
    60 function hwFloat2Float (const i: hwFloat) : extended; inline;
    62 
    61 
    63 // The implemented operators
    62 // The implemented operators
    64 
    63 
    65 operator = (const z1, z2: hwFloat) z : boolean; inline;
    64 operator = (const z1, z2: hwFloat) z : boolean; inline;
    66 
    65 {$IFDEF PAS2C}
       
    66 operator <> (const z1, z2: hwFloat) z : boolean; inline;
       
    67 {$ENDIF}
    67 operator + (const z1, z2: hwFloat) z : hwFloat; inline;
    68 operator + (const z1, z2: hwFloat) z : hwFloat; inline;
    68 operator - (const z1, z2: hwFloat) z : hwFloat; inline;
    69 operator - (const z1, z2: hwFloat) z : hwFloat; inline;
    69 operator - (const z1: hwFloat) z : hwFloat; inline;
    70 operator - (const z1: hwFloat) z : hwFloat; inline;
    70 
    71 
    71 operator * (const z1, z2: hwFloat) z : hwFloat; inline;
    72 operator * (const z1, z2: hwFloat) z : hwFloat; inline;
    93 function vector2Angle(const x, y: hwFloat): LongInt;
    94 function vector2Angle(const x, y: hwFloat): LongInt;
    94 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.
    95 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.
    96 function hwSignf(r: real): 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.
    97 function isZero(const z: hwFloat): boolean; inline;
    98 function isZero(const z: hwFloat): boolean; inline;
    98 {$IFDEF FPC}
    99 
    99 {$J-}
       
   100 {$ENDIF}
       
   101 {$WARNINGS OFF}
   100 {$WARNINGS OFF}
   102 
       
   103 
       
   104 // some hwFloat constants
   101 // some hwFloat constants
   105 
       
   106 const  _1div1024: hwFloat = (isNegative: false; QWordValue:     4194304);
   102 const  _1div1024: hwFloat = (isNegative: false; QWordValue:     4194304);
   107       _1div10000: hwFloat = (isNegative: false; QWordValue:      429496);
   103       _1div10000: hwFloat = (isNegative: false; QWordValue:      429496);
   108       _1div50000: hwFloat = (isNegative: false; QWordValue:       85899);
   104       _1div50000: hwFloat = (isNegative: false; QWordValue:       85899);
   109      _1div100000: hwFloat = (isNegative: false; QWordValue:       42950);
   105      _1div100000: hwFloat = (isNegative: false; QWordValue:       42950);
   110           _1div3: hwFloat = (isNegative: false; QWordValue:  1431655766);
   106           _1div3: hwFloat = (isNegative: false; QWordValue:  1431655766);
   148            _0_96: hwFloat = (isNegative: false; QWordValue:  4123168604);
   144            _0_96: hwFloat = (isNegative: false; QWordValue:  4123168604);
   149           _0_995: hwFloat = (isNegative: false; QWordValue:  4273492459);
   145           _0_995: hwFloat = (isNegative: false; QWordValue:  4273492459);
   150           _0_999: hwFloat = (isNegative: false; QWordValue:  4290672328);
   146           _0_999: hwFloat = (isNegative: false; QWordValue:  4290672328);
   151               _0: hwFloat = (isNegative: false; QWordValue:           0);
   147               _0: hwFloat = (isNegative: false; QWordValue:           0);
   152               _1: hwFloat = (isNegative: false; QWordValue:  4294967296);
   148               _1: hwFloat = (isNegative: false; QWordValue:  4294967296);
   153             _1_2: hwFloat = (isNegative: false; QWordValue:  1288490189*4);
   149             _1_2: hwFloat = (isNegative: false; QWordValue:  4294967296 * 6 div 5 + 1);
   154             _1_5: hwFloat = (isNegative: false; QWordValue:  4294967296 * 3 div 2);
   150             _1_5: hwFloat = (isNegative: false; QWordValue:  4294967296 * 3 div 2);
   155             _1_6: hwFloat = (isNegative: false; QWordValue:  4294967296 * 8 div 5);
   151             _1_6: hwFloat = (isNegative: false; QWordValue:  4294967296 * 8 div 5);
   156             _1_9: hwFloat = (isNegative: false; QWordValue:  8160437862);
   152             _1_9: hwFloat = (isNegative: false; QWordValue:  8160437862);
   157               _2: hwFloat = (isNegative: false; QWordValue:  4294967296 * 2);
   153               _2: hwFloat = (isNegative: false; QWordValue:  4294967296 * 2);
   158             _2_4: hwFloat = (isNegative: false; QWordValue:  4294967296 * 12 div 5);
   154             _2_4: hwFloat = (isNegative: false; QWordValue:  4294967296 * 12 div 5);
   159               _3: hwFloat = (isNegative: false; QWordValue:  4294967296 * 3);
   155               _3: hwFloat = (isNegative: false; QWordValue:  4294967296 * 3);
   160             _3_2: hwFloat = (isNegative: false; QWordValue:  3435973837*4);
   156             _3_2: hwFloat = (isNegative: false; QWordValue:  4294967296 * 16 div 5);
   161              _PI: hwFloat = (isNegative: false; QWordValue: 13493037704);
   157              _PI: hwFloat = (isNegative: false; QWordValue: 13493037704);
   162               _4: hwFloat = (isNegative: false; QWordValue:  4294967296 * 4);
   158               _4: hwFloat = (isNegative: false; QWordValue:  4294967296 * 4);
   163             _4_5: hwFloat = (isNegative: false; QWordValue:  4294967296 * 9 div 2);
   159             _4_5: hwFloat = (isNegative: false; QWordValue:  4294967296 * 9 div 2);
   164               _5: hwFloat = (isNegative: false; QWordValue:  4294967296 * 5);
   160               _5: hwFloat = (isNegative: false; QWordValue:  4294967296 * 5);
   165               _6: hwFloat = (isNegative: false; QWordValue:  4294967296 * 6);
   161               _6: hwFloat = (isNegative: false; QWordValue:  4294967296 * 6);
   166             _6_4: hwFloat = (isNegative: false; QWordValue:  3435973837 * 8);
   162             _6_4: hwFloat = (isNegative: false; QWordValue:  4294967296 * 32 div 5);
   167               _7: hwFloat = (isNegative: false; QWordValue:  4294967296 * 7);
   163               _7: hwFloat = (isNegative: false; QWordValue:  4294967296 * 7);
   168              _10: hwFloat = (isNegative: false; QWordValue:  4294967296 * 10);
   164              _10: hwFloat = (isNegative: false; QWordValue:  4294967296 * 10);
   169              _12: hwFloat = (isNegative: false; QWordValue:  4294967296 * 12);
   165              _12: hwFloat = (isNegative: false; QWordValue:  4294967296 * 12);
   170              _16: hwFloat = (isNegative: false; QWordValue:  4294967296 * 16);
   166              _16: hwFloat = (isNegative: false; QWordValue:  4294967296 * 16);
   171              _19: hwFloat = (isNegative: false; QWordValue:  4294967296 * 19);
   167              _19: hwFloat = (isNegative: false; QWordValue:  4294967296 * 19);
   192           _10000: hwFloat = (isNegative: false; QWordValue:  4294967296 * 10000);
   188           _10000: hwFloat = (isNegative: false; QWordValue:  4294967296 * 10000);
   193 
   189 
   194          cLittle: hwFloat = (isNegative: false; QWordValue:           1);
   190          cLittle: hwFloat = (isNegative: false; QWordValue:           1);
   195          cHHKick: hwFloat = (isNegative: false; QWordValue:    42949673);  // _0_01
   191          cHHKick: hwFloat = (isNegative: false; QWordValue:    42949673);  // _0_01
   196 {$WARNINGS ON}
   192 {$WARNINGS ON}
   197 {$ENDIF}
       
   198 
       
   199 {$IFNDEF FPC}
       
   200 type hwFloat = Extended;
       
   201 {$ENDIF}
       
   202 
   193 
   203 implementation
   194 implementation
   204 uses uSinTable;
   195 uses uSinTable;
   205 
   196 
   206 
       
   207 {$IFDEF FPC}
       
   208 
   197 
   209 function int2hwFloat (const i: LongInt) : hwFloat; inline;
   198 function int2hwFloat (const i: LongInt) : hwFloat; inline;
   210 begin
   199 begin
   211 int2hwFloat.isNegative:= i < 0;
   200 int2hwFloat.isNegative:= i < 0;
   212 int2hwFloat.Round:= abs(i);
   201 int2hwFloat.Round:= abs(i);
   222 
   211 
   223 operator = (const z1, z2: hwFloat) z : boolean; inline;
   212 operator = (const z1, z2: hwFloat) z : boolean; inline;
   224 begin
   213 begin
   225     z:= (z1.isNegative = z2.isNegative) and (z1.QWordValue = z2.QWordValue);
   214     z:= (z1.isNegative = z2.isNegative) and (z1.QWordValue = z2.QWordValue);
   226 end;
   215 end;
       
   216 
       
   217 {$IFDEF PAS2C}
       
   218 operator <> (const z1, z2: hwFloat) z : boolean; inline;
       
   219 begin
       
   220     z:= (z1.isNegative <> z2.isNegative) or (z1.QWordValue <> z2.QWordValue);
       
   221 end;
       
   222 {$ENDIF}
   227 
   223 
   228 operator + (const z1, z2: hwFloat) z : hwFloat; inline;
   224 operator + (const z1, z2: hwFloat) z : hwFloat; inline;
   229 begin
   225 begin
   230 if z1.isNegative = z2.isNegative then
   226 if z1.isNegative = z2.isNegative then
   231     begin
   227     begin
   292         b:= (z1.QWordValue > z2.QWordValue) <> z2.isNegative
   288         b:= (z1.QWordValue > z2.QWordValue) <> z2.isNegative
   293 end;
   289 end;
   294 
   290 
   295 operator - (const z1: hwFloat) z : hwFloat; inline;
   291 operator - (const z1: hwFloat) z : hwFloat; inline;
   296 begin
   292 begin
   297 z:= z1;
   293     z:= z1;
   298 z.isNegative:= not z.isNegative
   294     z.isNegative:= not z.isNegative
   299 end;
   295 end;
   300 
   296 
   301 
   297 
   302 operator * (const z1, z2: hwFloat) z : hwFloat; inline;
   298 operator * (const z1, z2: hwFloat) z : hwFloat; inline;
   303 begin
   299 begin
   304 z.isNegative:= z1.isNegative xor z2.isNegative;
   300     z.isNegative:= z1.isNegative xor z2.isNegative;
   305 z.QWordValue:= QWord(z1.Round) * z2.Frac + QWord(z1.Frac) * z2.Round + ((QWord(z1.Frac) * z2.Frac) shr 32);
   301     z.QWordValue:= QWord(z1.Round) * z2.Frac + QWord(z1.Frac) * z2.Round + ((QWord(z1.Frac) * z2.Frac) shr 32);
   306 z.Round:= z.Round + QWord(z1.Round) * z2.Round;
   302     z.Round:= z.Round + QWord(z1.Round) * z2.Round;
   307 end;
   303 end;
   308 
   304 
   309 operator * (const z1: hwFloat; const z2: LongInt) z : hwFloat; inline;
   305 operator * (const z1: hwFloat; const z2: LongInt) z : hwFloat; inline;
   310 begin
   306 begin
   311 z.isNegative:= z1.isNegative xor (z2 < 0);
   307     z.isNegative:= z1.isNegative xor (z2 < 0);
   312 z.QWordValue:= z1.QWordValue * abs(z2)
   308     z.QWordValue:= z1.QWordValue * abs(z2)
   313 end;
   309 end;
   314 
   310 
   315 operator / (const z1: hwFloat; z2: hwFloat) z : hwFloat; inline;
   311 operator / (const z1: hwFloat; z2: hwFloat) z : hwFloat; inline;
   316 var t: QWord;
   312 var t: QWord;
   317 begin
   313 begin
   318 z.isNegative:= z1.isNegative xor z2.isNegative;
   314     z.isNegative:= z1.isNegative xor z2.isNegative;
   319 z.Round:= z1.QWordValue div z2.QWordValue;
   315     z.Round:= z1.QWordValue div z2.QWordValue;
   320 t:= z1.QWordValue - z2.QWordValue * z.Round;
   316     t:= z1.QWordValue - z2.QWordValue * z.Round;
   321 z.Frac:= 0;
   317     z.Frac:= 0;
   322 
   318 
   323 if t <> 0 then
   319     if t <> 0 then
   324     begin
   320         begin
   325     while ((t and $FF00000000000000) = 0) and ((z2.QWordValue and $FF00000000000000) = 0) do
   321         while ((t and $FF00000000000000) = 0) and ((z2.QWordValue and $FF00000000000000) = 0) do
   326         begin
   322             begin
   327         t:= t shl 8;
   323             t:= t shl 8;
   328         z2.QWordValue:= z2.QWordValue shl 8
   324             z2.QWordValue:= z2.QWordValue shl 8
   329         end;
   325             end;
   330 
   326 
   331     if z2.Round > 0 then
   327         if z2.Round > 0 then
   332         inc(z.QWordValue, t div z2.Round);
   328             inc(z.QWordValue, t div z2.Round);
   333     end
   329         end
   334 end;
   330 end;
   335 
   331 
   336 operator / (const z1: hwFloat; const z2: LongInt) z : hwFloat; inline;
   332 operator / (const z1: hwFloat; const z2: LongInt) z : hwFloat; inline;
   337 begin
   333 begin
   338 z.isNegative:= z1.isNegative xor (z2 < 0);
   334     z.isNegative:= z1.isNegative xor (z2 < 0);
   339 z.QWordValue:= z1.QWordValue div abs(z2)
   335     z.QWordValue:= z1.QWordValue div abs(z2)
   340 end;
   336 end;
   341 
   337 
   342 function cstr(const z: hwFloat): shortstring;
   338 function cstr(const z: hwFloat): shortstring;
   343 var tmpstr: shortstring;
   339 var tmpstr: shortstring;
   344 begin
   340 begin
   345 str(z.Round, cstr);
   341     str(z.Round, cstr);
   346 if z.Frac <> 0 then
   342     if z.Frac <> 0 then
   347     begin
   343         begin
   348     str(z.Frac / $100000000, tmpstr);
   344         str(z.Frac / $100000000, tmpstr);
   349     delete(tmpstr, 1, 2);
   345         delete(tmpstr, 1, 2);
   350     cstr:= cstr + '.' + copy(tmpstr, 1, 10)
   346         cstr:= cstr + '.' + copy(tmpstr, 1, 10)
   351     end;
   347         end;
   352 if z.isNegative then
   348     if z.isNegative then
   353     cstr:= '-' + cstr
   349         cstr:= '-' + cstr
   354 end;
   350 end;
   355 
   351 
   356 function hwRound(const t: hwFloat): LongInt;
   352 function hwRound(const t: hwFloat): LongInt;
   357 begin
   353 begin
   358 if t.isNegative then
   354     if t.isNegative then
   359     hwRound:= -(t.Round and $7FFFFFFF)
   355         hwRound:= -(t.Round and $7FFFFFFF)
   360 else
   356     else
   361     hwRound:= t.Round and $7FFFFFFF
   357         hwRound:= t.Round and $7FFFFFFF
   362 end;
   358 end;
   363 
   359 
   364 function hwAbs(const t: hwFloat): hwFloat;
   360 function hwAbs(const t: hwFloat): hwFloat;
   365 begin
   361 begin
   366 hwAbs:= t;
   362     hwAbs:= t;
   367 hwAbs.isNegative:= false
   363     hwAbs.isNegative:= false
   368 end;
   364 end;
   369 
   365 
   370 function hwSqr(const t: hwFloat): hwFloat; inline;
   366 function hwSqr(const t: hwFloat): hwFloat; inline;
   371 begin
   367 begin
   372 hwSqr.isNegative:= false;
   368     hwSqr.isNegative:= false;
   373 hwSqr.QWordValue:= ((QWord(t.Round) * t.Round) shl 32) + QWord(t.Round) * t.Frac * 2 + ((QWord(t.Frac) * t.Frac) shr 32);
   369     hwSqr.QWordValue:= ((QWord(t.Round) * t.Round) shl 32) + QWord(t.Round) * t.Frac * 2 + ((QWord(t.Frac) * t.Frac) shr 32);
   374 end;
   370 end;
   375 
   371 
   376 function hwPow(const t: hwFloat;p: LongWord): hwFloat;
   372 function hwPow(const t: hwFloat;p: LongWord): hwFloat;
   377 begin
   373 begin
   378 hwPow:= t;
   374     hwPow:= t;
   379 if p mod 2 = 0 then hwPow.isNegative:= false;
   375     if p mod 2 = 0 then hwPow.isNegative:= false;
   380 
   376 
   381 while p > 0 do
   377     while p > 0 do
   382     begin
   378         begin
   383     hwPow.QWordValue:= QWord(hwPow.Round) * t.Frac + QWord(hwPow.Frac) * t.Round + ((QWord(hwPow.Frac) * t.Frac) shr 32);
   379         hwPow.QWordValue:= QWord(hwPow.Round) * t.Frac + QWord(hwPow.Frac) * t.Round + ((QWord(hwPow.Frac) * t.Frac) shr 32);
   384     dec(p)
   380         dec(p)
   385     end
   381         end
   386 end;
   382 end;
   387 
   383 
   388 function hwSqrt1(const t: hwFloat): hwFloat;
   384 function hwSqrt1(const t: hwFloat): hwFloat;
   389 const pwr = 8; // even value, feel free to adjust
   385 const pwr = 8; // even value, feel free to adjust
   390       rThreshold = 1 shl (pwr + 32);
   386       rThreshold = 1 shl (pwr + 32);
   391       lThreshold = 1 shl (pwr div 2 + 32);
   387       lThreshold = 1 shl (pwr div 2 + 32);
   392 var l, r: QWord;
   388 var l, r: QWord;
   393     c: hwFloat;
   389     c: hwFloat;
   394 begin
   390 begin
   395 hwSqrt1.isNegative:= false;
   391     hwSqrt1.isNegative:= false;
   396 
   392 
   397 if t.Round = 0 then
   393     if t.Round = 0 then
   398     begin
   394         begin
   399     l:= t.QWordValue;
   395         l:= t.QWordValue;
   400     r:= $100000000
   396         r:= $100000000
   401     end
   397         end
   402 else
   398     else
   403     begin
   399         begin
   404     if t.QWordValue > $FFFFFFFFFFFF then // t.Round > 65535.9999
   400         if t.QWordValue > $FFFFFFFFFFFF then // t.Round > 65535.9999
   405         begin
       
   406         l:= $10000000000; // 256
       
   407         r:= $FFFFFFFFFFFF; // 65535.9999
       
   408         end else
       
   409         if t.QWordValue >= rThreshold then
       
   410             begin
   401             begin
   411             l:= lThreshold;
   402             l:= $10000000000; // 256
   412             r:= $10000000000; // 256
   403             r:= $FFFFFFFFFFFF; // 65535.9999
   413             end else
   404             end
   414             begin
   405         else
   415             l:= $100000000;
   406             if t.QWordValue >= rThreshold then
   416             r:= lThreshold;
   407                 begin
   417             end;
   408                 l:= lThreshold;
       
   409                 r:= $10000000000; // 256
       
   410                 end
       
   411             else
       
   412                 begin
       
   413                 l:= $100000000;
       
   414                 r:= lThreshold;
       
   415                 end;
   418     end;
   416     end;
   419 
   417 
   420 repeat
   418     repeat
   421     c.QWordValue:= (l + r) shr 1;
   419         c.QWordValue:= (l + r) shr 1;
   422     if hwSqr(c).QWordValue > t.QWordValue then
   420         if hwSqr(c).QWordValue > t.QWordValue then
   423         r:= c.QWordValue
   421             r:= c.QWordValue
   424     else
   422         else
   425         l:= c.QWordValue
   423             l:= c.QWordValue
   426 until r - l <= 1;
   424     until r - l <= 1;
   427 
   425 
   428 hwSqrt1.QWordValue:= l
   426     hwSqrt1.QWordValue:= l
   429 end;
   427 end;
   430 
   428 
   431 function hwSqrt(const x: hwFloat): hwFloat;
   429 function hwSqrt(const x: hwFloat): hwFloat;
   432 var r, t, s, q: QWord;
   430 var r, t, s, q: QWord;
   433     i: integer;
   431     i: integer;
   434 begin
   432 begin
   435 hwSqrt.isNegative:= false;
   433     hwSqrt.isNegative:= false;
   436 
   434 
   437 t:= $4000000000000000;
   435     t:= $4000000000000000;
   438 r:= 0;
   436     r:= 0;
   439 q:= x.QWordValue;
   437     q:= x.QWordValue;
   440 
   438 
   441 for i:= 0 to 31 do
   439     for i:= 0 to 31 do
   442     begin
   440         begin
   443     s:= r + t;
   441         s:= r + t;
   444     r:= r shr 1;
   442         r:= r shr 1;
   445     if s <= q then
   443         if s <= q then
   446         begin
   444             begin
   447         dec(q, s);
   445             dec(q, s);
   448         inc(r, t);
   446             inc(r, t);
       
   447             end;
       
   448         t:= t shr 2;
   449         end;
   449         end;
   450     t:= t shr 2;
   450 
   451     end;
   451     hwSqrt.QWordValue:= r shl 16
   452 
       
   453 hwSqrt.QWordValue:= r shl 16
       
   454 end;
   452 end;
   455 
   453 
   456 
   454 
   457 
   455 
   458 function Distance(const dx, dy: hwFloat): hwFloat;
   456 function Distance(const dx, dy: hwFloat): hwFloat;
   459 var r: QWord;
   457 var r: QWord;
   460 begin
   458 begin
   461 r:= dx.QWordValue or dy.QWordValue;
   459     r:= dx.QWordValue or dy.QWordValue;
   462 
   460 
   463 if r < $10000 then
   461     if r < $10000 then
   464     begin
   462         begin
   465     Distance.QWordValue:= r;
   463         Distance.QWordValue:= r;
   466     Distance.isNegative:= false
   464         Distance.isNegative:= false
   467     end else
   465         end
   468     Distance:= hwSqrt(hwSqr(dx) + hwSqr(dy))
   466     else
       
   467         Distance:= hwSqrt(hwSqr(dx) + hwSqr(dy))
   469 end;
   468 end;
   470 
   469 
   471 function DistanceI(const dx, dy: LongInt): hwFloat;
   470 function DistanceI(const dx, dy: LongInt): hwFloat;
   472 begin
   471 begin
   473 DistanceI:= hwSqrt(int2hwFloat(sqr(dx) + sqr(dy)))
   472     DistanceI:= hwSqrt(int2hwFloat(sqr(dx) + sqr(dy)))
   474 end;
   473 end;
   475 
   474 
   476 function SignAs(const num, signum: hwFloat): hwFloat;
   475 function SignAs(const num, signum: hwFloat): hwFloat;
   477 begin
   476 begin
   478 SignAs.QWordValue:= num.QWordValue;
   477     SignAs.QWordValue:= num.QWordValue;
   479 SignAs.isNegative:= signum.isNegative
   478     SignAs.isNegative:= signum.isNegative
   480 end;
   479 end;
   481 
   480 
   482 function hwSign(r: hwFloat): LongInt;
   481 function hwSign(r: hwFloat): LongInt;
   483 begin
   482 begin
   484 // yes, we have negative zero for a reason
   483 // yes, we have negative zero for a reason
   547     if y.isNegative then c:= - c;
   546     if y.isNegative then c:= - c;
   548 
   547 
   549     vector2Angle:= c
   548     vector2Angle:= c
   550 end;
   549 end;
   551 
   550 
   552 {$ENDIF}
       
   553 
       
   554 end.
   551 end.