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:
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:
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.
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;
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;
{$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.