Probleme mit Fix64

  • 1
  • 2
  • 3
  • 4
  • 5
  • Page 4 of 5
Avra
Schreiberling
Avatar
Gender:
Location: Belgrade, Serbia
Age: 53
Homepage: rs.linkedin.com/in…
Posts: 653
Registered: 07 / 2002
Subject:

Re: Probleme mit Fix64

 · 
Posted: 21.04.2013 - 01:26  ·  #25
Hello Rolf,

There isn't a problem with very small positive numbers since the reason for Michael getting -1 was the line with Dec(Tmp.i) command which was there just for special case correction of negative numbers and was originally triggered when float number was negative and instead it should only trigger when float number was less or equal then -2.3283064365386962890625E-10 (yes, I know that float can handle only -2.328307E-10 with less significant digits but compiler lets me type the exact number so I have left it like that). Here is the corrected code which should be closer to original and easier to understand:

Code
function FloatToFix64(const a: float): fix64;
var
  Tmp: TFix64Overlay;
begin
  Tmp.i := Trunc(a);
  if (a <= -2.3283064365386962890625E-10) and (Frac(a) <> 0) then
    Dec(Tmp.i);
  endif;
  Tmp.f := Trunc(Frac(a) * (float($FFFFFFFF) + 1));
  return(Tmp.fix);
end;


I do not think that it would be good to return -2.3283064365386962890625E-10 (approximate precision of a single bit in fix64 number) for all numbers greater then that and less then 0. We have to draw a line somewhere and that should be -2.3283064365386962890625E-10. User should always check for zero before division, and I also handle special zero cases in fixed point numbers library as a protection. Just take a look at this function implementation:

Code
function Fix64Tan(const rad: fix64): fix64;
{$IFDEF FIX64_USE_CORRECTION_TRIGONOMETRY_TABLE} // correction to get cos(90) = 0.000000000 instead of 0.000000012
var
  TmpSin, TmpCos: fix64;
begin
  TmpSin := fix64Sin(rad);
  TmpCos := fix64Cos(rad);
  if TmpCos <> 0.0 then
    return(Fix64Div(TmpSin, TmpCos));
  else
    if TmpSin < 0.0 then
      return(fix64(FIX_MIN));
    else
      return(fix64(FIX_MAX));
    endif;
  endif;
{$ELSE}                                          // no correction
begin
  return(Fix64Div(Fix64Sin(rad), fix64Cos(rad))); // tan() = sin() / cos()
{$ENDIF}
end;

You can see that if FIX64_USE_CORRECTION_TRIGONOMETRY_TABLE define is used then I handle special zero case (because cos(90) might have been corrected to 0.000000000 in that case) and function returns correct "infinity number" (which does not do any other library that I have seen), and if that define is not used then simple division is used and we also don't have to worry since cos(90) is 0.000000012 (it's not corrected to 0) and there is no division by zero.
;-)
rh
Administrator
Avatar
Gender:
Location: Germany
Age: 24
Homepage: e-lab.de
Posts: 5558
Registered: 03 / 2002
Subject:

Re: Probleme mit Fix64

 · 
Posted: 21.04.2013 - 15:41  ·  #26
Hello Avra,

thankyou.

rolf
mc-electronic
Benutzer
Avatar
Gender: n/a
Location: Sauerland NRW
Posts: 372
Registered: 03 / 2008
Subject:

Re: Probleme mit Fix64

 · 
Posted: 22.04.2013 - 08:42  ·  #27
Hi Rolf, hi Avra,

great job, thank you!

I am using the Fix64 for integration purpose of floating measurements. Than means, that the integrated value may accumulate to big numbers (e.g. > 1E06), but there are only very very small values (e.g. 1E-06) that are added up to this big number, but many times each second. That does not work with the 4 Byte Floating Point variables, as you can imagine. There, the adding up is rounded away due to the high value - you can not have all: big value, small fraction AND precision. Then, when I started to handle fraction and pre-comma Integer Value separately, Avra came up with the 64 Bit Fix libary, which solved all these problems right away. Fantastic code, very fast!!

A customer of mine noticed erratic values in his system, where very small negative values all of a sudden changed to huge numbers. Finding the bug was quite a challenge..

As always, I am impressed and glad, how fast and thoroghly things get taken up here and solved.

Have a nice week, Michael
rh
Administrator
Avatar
Gender:
Location: Germany
Age: 24
Homepage: e-lab.de
Posts: 5558
Registered: 03 / 2002
Subject:

Re: Probleme mit Fix64

 · 
Posted: 22.04.2013 - 11:22  ·  #28
Hello Michael,

please take in mind that Avra's implementation of FloatToFix returns a zero with very small float numbers.

rolf
Avra
Schreiberling
Avatar
Gender:
Location: Belgrade, Serbia
Age: 53
Homepage: rs.linkedin.com/in…
Posts: 653
Registered: 07 / 2002
Subject:

Re: Probleme mit Fix64

 · 
Posted: 22.04.2013 - 16:57  ·  #29
Hello all,

I think I owe everyone a little clarification. Replacing loop in Fix64 Demo1 with this code:
Code
  fixNum := 0.0;
  loop
    LCDxy_M(LCD_m1, 0, 0);
    Write(LCDout_M, 'Binary: ' + IntToBin(fixNumOvr.w[3]) + IntToBin(fixNumOvr.w[2]));
    LCDxy_M(LCD_m1, 0, 1);
    Write(LCDout_M, 'Fix64:  ' + Fix64ToString(fixNum) + '   ');
    LCDxy_M(LCD_m2, 0, 0);
    Write(LCDout_M, IntToBin(fixNumOvr.w[1]) + IntToBin(fixNumOvr.w[0]));
    LCDxy_M(LCD_m2, 0, 1);
    Write(LCDout_M, 'Hex: ' + LongToHex(fixNumOvr.i) + DecimalSep + LongToHex(fixNumOvr.f));
    Dec(fixNumOvr.i64); // decrement for just single bit - breakpoint should be put here
  endloop;

Should give you something like in the attached image. Everything is explained in the image. Please take a look. It is now clear why I convert only very, very small negative numbers (between -2.3283064365386962890625E-10 and 0.0) to zero. Only because of technical reasons - there is just a single bit between these two numbers so we have to decide what it will be, one or the other number.

If anyone is willing to test if the same bug exists in Delphi/Lazarus unit mentioned at topic.php?t=2659&highlight=fix64&page=2, I am willing to correct it if needed.
Attachments
Probleme mit Fix64
Filename: fix64-explained.png
Filesize: 20.84 KB
Title:
Download counter: 120
mc-electronic
Benutzer
Avatar
Gender: n/a
Location: Sauerland NRW
Posts: 372
Registered: 03 / 2008
Subject:

Re: Probleme mit Fix64

 · 
Posted: 08.05.2014 - 09:44  ·  #30
Hello Rolf, hello Avra,

I have encountered a problem with Fix64 and defining them as a constant: If I do the following definition

Const
gFixHx64 : Array [1..20] Of Fix64 = (-0.0004909965, 0.08183197, -0.0005552967, -0.00002228376, -0.0000006211808, -0.000191275, 0.07258, -0.0002939, 0.0000009841, -0.00000000192, -61.125785, 8.1386, -0.07422003, 0.06283721, -0.0027237063, -63.16113, 5.36859, 0.973587, -0.0738636, 0.00481832);
...
// And then list the numbers:
For lCnt := 1 To 20 Do
SLIP_WriteStr('TXT|gFixHx64['+ByteToStr(lCnt)+']: '+Fix64ToStr(gFixHx64[lCnt]));
EndFor;

// I get the following output - you see, the e.g. gFixHx64[2] or gFixHx64[7] are completely wrong before the decimal point:

gFixHx64[1]: -0.000490997
gFixHx64[2]: 20.081831970
gFixHx64[3]: -0.000555297
gFixHx64[4]: -0.000022284
gFixHx64[5]: -0.000000621
gFixHx64[6]: -0.000191275
gFixHx64[7]: 18.072580000
gFixHx64[8]: -0.000293900
gFixHx64[9]: 0.000000984
gFixHx64[10]: -0.000000002
gFixHx64[11]: -4013344.125785000
gFixHx64[12]: 526371.138600000
gFixHx64[13]: -19.074220030
gFixHx64[14]: 16.062837210
gFixHx64[15]: -0.002723706
gFixHx64[16]: -4144937.161130000
gFixHx64[17]: 329054.368590000
gFixHx64[18]: 249.973587000
gFixHx64[19]: -18.073863600
gFixHx64[20]: 1.004818320

However, if I define them as Variables and set them in the INI-Part of my program, all is good:

Var
gFixHx64 : Array [1..20] Of Fix64;
...
// Setting in INI:

gFixHx64[1] : = -0.0004909965;
gFixHx64[2] : = 0.08183197;
gFixHx64[3] : = -0.0005552967;
gFixHx64[4] : = -0.00002228376;
gFixHx64[5] : = -0.0000006211808;
gFixHx64[6] : = -0.000191275;
gFixHx64[7] : = 0.07258;
gFixHx64[8] : = -0.0002939;
gFixHx64[9] : = 0.0000009841;
gFixHx64[10] : = -0.00000000192;
gFixHx64[11] : = -61.125785;
gFixHx64[12] : = 8.1386;
gFixHx64[13] : = -0.07422003;
gFixHx64[14] : = 0.06283721;
gFixHx64[15] : = -0.0027237063;
gFixHx64[16] : = -63.16113;
gFixHx64[17] : = 5.36859;
gFixHx64[18] : = 0.973587;
gFixHx64[19] : = -0.0738636;
gFixHx64[20] : = 0.00481832;

// Doing the output:

For lCnt := 1 To 20 Do
SLIP_WriteStr('TXT|gFixHx64['+ByteToStr(lCnt)+']: '+Fix64ToStr(gFixHx64[lCnt]));
EndFor;

// Result OK:

gFixHx64[1]: -0.000490997
gFixHx64[2]: 0.081831970
gFixHx64[3]: -0.000555297
gFixHx64[4]: -0.000022284
gFixHx64[5]: -0.000000621
gFixHx64[6]: -0.000191275
gFixHx64[7]: 0.072580000
gFixHx64[8]: -0.000293900
gFixHx64[9]: 0.000000984
gFixHx64[10]: -0.000000002
gFixHx64[11]: -61.125785000
gFixHx64[12]: 8.138600000
gFixHx64[13]: -0.074220030
gFixHx64[14]: 0.062837210
gFixHx64[15]: -0.002723706
gFixHx64[16]: -63.161130000
gFixHx64[17]: 5.368590000
gFixHx64[18]: 0.973587000
gFixHx64[19]: -0.073863600
gFixHx64[20]: 0.004818320

Please advise!

Michael
rh
Administrator
Avatar
Gender:
Location: Germany
Age: 24
Homepage: e-lab.de
Posts: 5558
Registered: 03 / 2002
Subject:

Re: Probleme mit Fix64

 · 
Posted: 08.05.2014 - 15:51  ·  #31
Hallo Michael,
Bug erkannt, Bug gebannt :aerger:
Der Zugriff auf Flash gebundene Arrays mit 64bit Konstanten war fehlerhaft.
Beseitigt und tut jetzt.

Neues Update steht ca. 17Uhr zum Download bereit. Gleiche REV!

rolf
mc-electronic
Benutzer
Avatar
Gender: n/a
Location: Sauerland NRW
Posts: 372
Registered: 03 / 2008
Subject:

Re: Probleme mit Fix64

 · 
Posted: 08.05.2014 - 18:01  ·  #32
Hallo Rolf,

ja super! Jetzt tut es auch bei mir. Spart viel Flash und da bin ich knapp. Hatte für einen Kunden eine Taupunkts-Ermittelung nach h,x Diagramm programmiert und da braucht man genaue Berechnungen - mit den normalen Floats klappt das nicht. Super-Sache diese Fix64!!

Danke!
  • 1
  • 2
  • 3
  • 4
  • 5
  • Page 4 of 5
Selected quotes for multi-quoting:   0

Registered users in this topic

Currently no registered users in this section

The statistic shows who was online during the last 5 minutes. Updated every 90 seconds.
MySQL Queries: 16 · Cache Hits: 15   131   146 · Page-Gen-Time: 0.045487s · Memory Usage: 2 MB · GZIP: on · Viewport: SMXL-HiDPI