hedgewars/uFloat.pas
changeset 6580 6155187bf599
parent 6498 5678806aafca
child 6700 e04da46ee43c
equal deleted inserted replaced
6579:fc52f7c22c9b 6580:6155187bf599
    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;
   198 end;
   198 end;
   199 
   199 
   200 function hwFloat2Float (const i: hwFloat) : extended;
   200 function hwFloat2Float (const i: hwFloat) : extended;
   201 begin
   201 begin
   202 hwFloat2Float:= i.QWordValue / $100000000;
   202 hwFloat2Float:= i.QWordValue / $100000000;
   203 if i.isNegative then hwFloat2Float:= -hwFloat2Float;
   203 if i.isNegative then
       
   204     hwFloat2Float:= -hwFloat2Float;
   204 end;
   205 end;
   205 
   206 
   206 operator = (const z1, z2: hwFloat) z : boolean; inline;
   207 operator = (const z1, z2: hwFloat) z : boolean; inline;
   207 begin
   208 begin
   208     z:= (z1.isNegative = z2.isNegative) and (z1.QWordValue = z2.QWordValue);
   209     z:= (z1.isNegative = z2.isNegative) and (z1.QWordValue = z2.QWordValue);
   210 
   211 
   211 
   212 
   212 operator + (const z1, z2: hwFloat) z : hwFloat;
   213 operator + (const z1, z2: hwFloat) z : hwFloat;
   213 begin
   214 begin
   214 if z1.isNegative = z2.isNegative then
   215 if z1.isNegative = z2.isNegative then
   215    begin
   216     begin
   216    z.isNegative:= z1.isNegative;
   217     z.isNegative:= z1.isNegative;
   217    z.QWordValue:= z1.QWordValue + z2.QWordValue
   218     z.QWordValue:= z1.QWordValue + z2.QWordValue
   218    end
   219     end
   219 else
   220 else
   220    if z1.QWordValue > z2.QWordValue then
   221     if z1.QWordValue > z2.QWordValue then
   221       begin
   222         begin
   222       z.isNegative:= z1.isNegative;
   223         z.isNegative:= z1.isNegative;
   223       z.QWordValue:= z1.QWordValue - z2.QWordValue
   224         z.QWordValue:= z1.QWordValue - z2.QWordValue
   224       end else
   225         end
   225       begin
   226     else
   226       z.isNegative:= z2.isNegative;
   227         begin
   227       z.QWordValue:= z2.QWordValue - z1.QWordValue
   228         z.isNegative:= z2.isNegative;
   228       end
   229         z.QWordValue:= z2.QWordValue - z1.QWordValue
       
   230         end
   229 end;
   231 end;
   230 
   232 
   231 operator - (const z1, z2: hwFloat) z : hwFloat;
   233 operator - (const z1, z2: hwFloat) z : hwFloat;
   232 begin
   234 begin
   233 if z1.isNegative = z2.isNegative then
   235 if z1.isNegative = z2.isNegative then
   234    if z1.QWordValue > z2.QWordValue then
   236     if z1.QWordValue > z2.QWordValue then
   235       begin
   237         begin
   236       z.isNegative:= z1.isNegative;
   238         z.isNegative:= z1.isNegative;
   237       z.QWordValue:= z1.QWordValue - z2.QWordValue
   239         z.QWordValue:= z1.QWordValue - z2.QWordValue
   238       end else
   240         end
   239       begin
   241     else
   240       z.isNegative:= not z2.isNegative;
   242         begin
   241       z.QWordValue:= z2.QWordValue - z1.QWordValue
   243         z.isNegative:= not z2.isNegative;
   242       end
   244         z.QWordValue:= z2.QWordValue - z1.QWordValue
   243 else begin
   245         end
   244      z.isNegative:= z1.isNegative;
   246 else
   245      z.QWordValue:= z1.QWordValue + z2.QWordValue
   247     begin
   246      end
   248     z.isNegative:= z1.isNegative;
       
   249     z.QWordValue:= z1.QWordValue + z2.QWordValue
       
   250     end
   247 end;
   251 end;
   248 
   252 
   249 operator - (const z1: hwFloat) z : hwFloat;
   253 operator - (const z1: hwFloat) z : hwFloat;
   250 begin
   254 begin
   251 z:= z1;
   255 z:= z1;
   254 
   258 
   255 
   259 
   256 operator * (const z1, z2: hwFloat) z : hwFloat;
   260 operator * (const z1, z2: hwFloat) z : hwFloat;
   257 begin
   261 begin
   258 z.isNegative:= z1.isNegative xor z2.isNegative;
   262 z.isNegative:= z1.isNegative xor z2.isNegative;
   259 z.QWordValue:= QWord(z1.Round) * z2.Frac +
   263 z.QWordValue:= QWord(z1.Round) * z2.Frac + QWord(z1.Frac) * z2.Round + ((QWord(z1.Frac) * z2.Frac) shr 32);
   260                QWord(z1.Frac) * z2.Round +
       
   261                ((QWord(z1.Frac) * z2.Frac) shr 32);
       
   262 z.Round:= z.Round + QWord(z1.Round) * z2.Round;
   264 z.Round:= z.Round + QWord(z1.Round) * z2.Round;
   263 end;
   265 end;
   264 
   266 
   265 operator * (const z1: hwFloat; const z2: LongInt) z : hwFloat;
   267 operator * (const z1: hwFloat; const z2: LongInt) z : hwFloat;
   266 begin
   268 begin
   273 begin
   275 begin
   274 z.isNegative:= z1.isNegative xor z2.isNegative;
   276 z.isNegative:= z1.isNegative xor z2.isNegative;
   275 z.Round:= z1.QWordValue div z2.QWordValue;
   277 z.Round:= z1.QWordValue div z2.QWordValue;
   276 t:= z1 - z2 * z.Round;
   278 t:= z1 - z2 * z.Round;
   277 if t.QWordValue = 0 then
   279 if t.QWordValue = 0 then
   278    z.Frac:= 0
   280     z.Frac:= 0
   279 else
   281 else
   280    begin
   282     begin
   281    while ((t.QWordValue and $8000000000000000) = 0) and
   283     while ((t.QWordValue and $8000000000000000) = 0) and ((z2.QWordValue and $8000000000000000) = 0) do
   282          ((z2.QWordValue and $8000000000000000) = 0) do
   284         begin
   283          begin
   285         t.QWordValue:= t.QWordValue shl 1;
   284          t.QWordValue:= t.QWordValue shl 1;
   286         z2.QWordValue:= z2.QWordValue shl 1
   285          z2.QWordValue:= z2.QWordValue shl 1
   287         end;
   286          end;
   288     if z2.Round > 0 then
   287    if z2.Round > 0 then z.Frac:= (t.QWordValue) div (z2.Round)
   289         z.Frac:= (t.QWordValue) div (z2.Round)
   288                    else z.Frac:= 0
   290     else
   289    end
   291         z.Frac:= 0
       
   292     end
   290 end;
   293 end;
   291 
   294 
   292 operator / (const z1: hwFloat; const z2: LongInt) z : hwFloat;
   295 operator / (const z1: hwFloat; const z2: LongInt) z : hwFloat;
   293 begin
   296 begin
   294 z.isNegative:= z1.isNegative xor (z2 < 0);
   297 z.isNegative:= z1.isNegative xor (z2 < 0);
   296 end;
   299 end;
   297 
   300 
   298 operator < (const z1, z2: hwFloat) b : boolean;
   301 operator < (const z1, z2: hwFloat) b : boolean;
   299 begin
   302 begin
   300 if z1.isNegative xor z2.isNegative then
   303 if z1.isNegative xor z2.isNegative then
   301    b:= z1.isNegative
   304     b:= z1.isNegative
   302 else
   305 else
   303    if z1.QWordValue = z2.QWordValue then
   306     if z1.QWordValue = z2.QWordValue then
   304       b:= false
   307         b:= false
   305    else
   308     else
   306       b:= (z1.QWordValue < z2.QWordValue) xor z1.isNegative
   309         b:= (z1.QWordValue < z2.QWordValue) xor z1.isNegative
   307 end;
   310 end;
   308 
   311 
   309 operator > (const z1, z2: hwFloat) b : boolean;
   312 operator > (const z1, z2: hwFloat) b : boolean;
   310 begin
   313 begin
   311 if z1.isNegative xor z2.isNegative then
   314 if z1.isNegative xor z2.isNegative then
   312    b:= z2.isNegative
   315     b:= z2.isNegative
   313 else
   316 else
   314    if z1.QWordValue = z2.QWordValue then
   317     if z1.QWordValue = z2.QWordValue then
   315       b:= false
   318         b:= false
   316    else
   319     else
   317       b:= (z1.QWordValue > z2.QWordValue) xor z2.isNegative
   320         b:= (z1.QWordValue > z2.QWordValue) xor z2.isNegative
   318 end;
   321 end;
   319 
   322 
   320 function cstr(const z: hwFloat): shortstring;
   323 function cstr(const z: hwFloat): shortstring;
   321 var tmpstr: shortstring;
   324 var tmpstr: shortstring;
   322 begin
   325 begin
   323 str(z.Round, cstr);
   326 str(z.Round, cstr);
   324 if z.Frac <> 0 then
   327 if z.Frac <> 0 then
   325    begin
   328     begin
   326    str(z.Frac / $100000000, tmpstr);
   329     str(z.Frac / $100000000, tmpstr);
   327    delete(tmpstr, 1, 2);
   330     delete(tmpstr, 1, 2);
   328    cstr:= cstr + '.' + copy(tmpstr, 1, 10)
   331     cstr:= cstr + '.' + copy(tmpstr, 1, 10)
   329    end;
   332     end;
   330 if z.isNegative then cstr:= '-' + cstr
   333 if z.isNegative then
       
   334     cstr:= '-' + cstr
   331 end;
   335 end;
   332 
   336 
   333 function hwRound(const t: hwFloat): LongInt;
   337 function hwRound(const t: hwFloat): LongInt;
   334 begin
   338 begin
   335 if t.isNegative then hwRound:= -(t.Round and $7FFFFFFF)
   339 if t.isNegative then
   336                 else hwRound:= t.Round and $7FFFFFFF
   340     hwRound:= -(t.Round and $7FFFFFFF)
       
   341 else
       
   342     hwRound:= t.Round and $7FFFFFFF
   337 end;
   343 end;
   338 
   344 
   339 function hwAbs(const t: hwFloat): hwFloat;
   345 function hwAbs(const t: hwFloat): hwFloat;
   340 begin
   346 begin
   341 hwAbs:= t;
   347 hwAbs:= t;
   343 end;
   349 end;
   344 
   350 
   345 function hwSqr(const t: hwFloat): hwFloat;
   351 function hwSqr(const t: hwFloat): hwFloat;
   346 begin
   352 begin
   347 hwSqr.isNegative:= false;
   353 hwSqr.isNegative:= false;
   348 hwSqr.QWordValue:=
   354 hwSqr.QWordValue:= ((QWord(t.Round) * t.Round) shl 32) + QWord(t.Round) * t.Frac * 2 + ((QWord(t.Frac) * t.Frac) shr 32);
   349       ((QWord(t.Round) * t.Round) shl 32)
       
   350     + QWord(t.Round) * t.Frac * 2
       
   351     + ((QWord(t.Frac) * t.Frac) shr 32);
       
   352 end;
   355 end;
   353 
   356 
   354 function hwSqrt(const t: hwFloat): hwFloat;
   357 function hwSqrt(const t: hwFloat): hwFloat;
   355 var l, r: QWord;
   358 var l, r: QWord;
   356     c: hwFloat;
   359     c: hwFloat;
   357 begin
   360 begin
   358 hwSqrt.isNegative:= false;
   361 hwSqrt.isNegative:= false;
   359 
   362 
   360 if t.Round = 0 then
   363 if t.Round = 0 then
   361    begin
   364     begin
   362    l:= t.QWordValue;
   365     l:= t.QWordValue;
   363    r:= $100000000
   366     r:= $100000000
   364    end else
   367     end
   365    begin
   368 else
   366    l:= $100000000;
   369     begin
   367    r:= t.QWordValue div 2 + $80000000; // r:= t / 2 + 0.5
   370     l:= $100000000;
   368    if r > $FFFFFFFFFFFF then r:= $FFFFFFFFFFFF
   371     r:= t.QWordValue div 2 + $80000000; // r:= t / 2 + 0.5
   369    end;
   372     if r > $FFFFFFFFFFFF then
       
   373         r:= $FFFFFFFFFFFF
       
   374     end;
   370 
   375 
   371 repeat
   376 repeat
   372   c.QWordValue:= (l + r) div 2;
   377     c.QWordValue:= (l + r) div 2;
   373   if hwSqr(c).QWordValue > t.QWordValue then r:= c.QWordValue else l:= c.QWordValue
   378     if hwSqr(c).QWordValue > t.QWordValue then
       
   379         r:= c.QWordValue
       
   380     else
       
   381         l:= c.QWordValue
   374 until r - l <= 1;
   382 until r - l <= 1;
   375 
   383 
   376 hwSqrt.QWordValue:= l
   384 hwSqrt.QWordValue:= l
   377 end;
   385 end;
   378 
   386 
   393 end;
   401 end;
   394 
   402 
   395 function hwSign(r: hwFloat): LongInt;
   403 function hwSign(r: hwFloat): LongInt;
   396 begin
   404 begin
   397 // yes, we have negative zero for a reason
   405 // yes, we have negative zero for a reason
   398 if r.isNegative then hwSign:= -1 else hwSign:= 1
   406 if r.isNegative then
       
   407     hwSign:= -1
       
   408 else
       
   409     hwSign:= 1
   399 end;
   410 end;
   400 
   411 
   401 
   412 
   402 function AngleSin(const Angle: Longword): hwFloat;
   413 function AngleSin(const Angle: Longword): hwFloat;
   403 begin
   414 begin
   404 //TryDo((Angle >= 0) and (Angle <= 2048), 'Sin param exceeds limits', true);
   415 //TryDo((Angle >= 0) and (Angle <= 2048), 'Sin param exceeds limits', true);
   405 AngleSin.isNegative:= false;
   416 AngleSin.isNegative:= false;
   406 if Angle < 1024 then AngleSin.QWordValue:= SinTable[Angle]
   417 if Angle < 1024 then
   407                 else AngleSin.QWordValue:= SinTable[2048 - Angle]
   418     AngleSin.QWordValue:= SinTable[Angle]
       
   419 else
       
   420     AngleSin.QWordValue:= SinTable[2048 - Angle]
   408 end;
   421 end;
   409 
   422 
   410 function AngleCos(const Angle: Longword): hwFloat;
   423 function AngleCos(const Angle: Longword): hwFloat;
   411 begin
   424 begin
   412 //TryDo((Angle >= 0) and (Angle <= 2048), 'Cos param exceeds limits', true);
   425 //TryDo((Angle >= 0) and (Angle <= 2048), 'Cos param exceeds limits', true);
   413 AngleCos.isNegative:= Angle > 1024;
   426 AngleCos.isNegative:= Angle > 1024;
   414 if Angle < 1024 then AngleCos.QWordValue:= SinTable[1024 - Angle]
   427 if Angle < 1024 then
   415                 else AngleCos.QWordValue:= SinTable[Angle - 1024]
   428     AngleCos.QWordValue:= SinTable[1024 - Angle]
       
   429 else
       
   430     AngleCos.QWordValue:= SinTable[Angle - 1024]
   416 end;
   431 end;
   417 
   432 
   418 function isZero(const z: hwFloat): boolean; inline; 
   433 function isZero(const z: hwFloat): boolean; inline; 
   419 begin
   434 begin
   420     isZero := z.QWordValue = 0;
   435 isZero := z.QWordValue = 0;
   421 end;
   436 end;
   422 {$ENDIF}
   437 {$ENDIF}
   423 
   438 
   424 end.
   439 end.