|
@@ -1160,10 +1160,222 @@ const
|
|
{$endif}
|
|
{$endif}
|
|
|
|
|
|
{$ifndef FPUNONE}
|
|
{$ifndef FPUNONE}
|
|
|
|
+
|
|
|
|
+(******************
|
|
|
|
+
|
|
|
|
+ Derived from: ".\Free Pascal\source\rtl\inc\genmath.inc"
|
|
|
|
+
|
|
|
|
+ Origin: "fast 10^n routine"
|
|
|
|
+ function FPower10(val: Extended; Power: Longint): Extended;
|
|
|
|
+
|
|
|
|
+ Changes:
|
|
|
|
+ > adapted to "ValReal", so float can be single/double/extended
|
|
|
|
+ > slightly changed arrays [redundant 58+2 float constants gone away]
|
|
|
|
+ > added some checks etc..
|
|
|
|
+
|
|
|
|
+ Notes:
|
|
|
|
+ > denormalization and overflow should go smooth if corresponding
|
|
|
|
+ FPU exceptions are masked [no external care needed by now]
|
|
|
|
+ > adaption to real48 and real128 is not hard if one needed
|
|
|
|
+
|
|
|
|
+ ******************)
|
|
|
|
+//
|
|
|
|
+ function mul_by_power10(x:ValReal;power:integer):ValReal;
|
|
|
|
+//
|
|
|
|
+// result:=X*(10^power)
|
|
|
|
+//
|
|
|
|
+// Routine achieves result with no more than 3 floating point mul/div's.
|
|
|
|
+// Up to ABS(power)=31, only 1 floating point mul/div is needed.
|
|
|
|
+//
|
|
|
|
+// Limitations:
|
|
|
|
+// for ValReal=extended : power=-5119..+5119
|
|
|
|
+// for ValReal=double : power=-319..+319
|
|
|
|
+// for ValReal=single : power=-63..+63
|
|
|
|
+//
|
|
|
|
+// If "power" is beyond this limits, routine gives up and returns 0/+INF/-INF.
|
|
|
|
+// This is not generally correct, but should be ok when routine is used only
|
|
|
|
+// as "VAL"-helper, since "x" exponent is reasonably close to 0 in this case.
|
|
|
|
+//
|
|
|
|
+//==================================
|
|
|
|
+{$IF DECLARED(C_HIGH_EXPBITS_5TO8)}
|
|
|
|
+ {$ERROR C_HIGH_EXPBITS_5TO8 declared somewhere in scope}
|
|
|
|
+{$ENDIF}
|
|
|
|
+
|
|
|
|
+{$IF DECLARED(C_HIGH_EXPBITS_9ANDUP)}
|
|
|
|
+ {$ERROR C_HIGH_EXPBITS_9ANDUP declared somewhere in scope}
|
|
|
|
+{$ENDIF}
|
|
|
|
+
|
|
|
|
+{$IF SIZEOF(ValReal)=10}
|
|
|
|
+//==================================
|
|
|
|
+// assuming "type ValReal=extended;"
|
|
|
|
+//
|
|
|
|
+type
|
|
|
|
+ TValRealRec = packed record
|
|
|
|
+ case byte of
|
|
|
|
+ 0: (
|
|
|
|
+ {$ifndef ENDIAN_BIG}
|
|
|
|
+ mant_lo, mant_hi : longword; expsign : word // little-endian/default
|
|
|
|
+ {$else}
|
|
|
|
+ expsign : word; mant_hi, mant_lo : longword // big-endian
|
|
|
|
+ {$endif}
|
|
|
|
+ );
|
|
|
|
+ 1: (v : extended);
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+const
|
|
|
|
+ {$ifndef ENDIAN_BIG}
|
|
|
|
+ // little-endian/default
|
|
|
|
+ C_INFTYP:TValRealRec=(mant_lo:0;mant_hi:$80000000;expsign:$7FFF); //+INF
|
|
|
|
+ C_INFTYM:TValRealRec=(mant_lo:0;mant_hi:$80000000;expsign:$FFFF); //-INF
|
|
|
|
+ {$else}
|
|
|
|
+ // big-endian
|
|
|
|
+ C_INFTYP:TValRealRec=(expsign:$7FFF;mant_hi:$80000000;mant_lo:0); //+INF
|
|
|
|
+ C_INFTYM:TValRealRec=(expsign:$FFFF;mant_hi:$80000000;mant_lo:0); //-INF
|
|
|
|
+ {$endif}
|
|
|
|
+
|
|
|
|
+ C_MAX_POWER = 5119;
|
|
|
|
+
|
|
|
|
+ C_HIGH_EXPBITS_5TO8 = 15;
|
|
|
|
+ C_HIGH_EXPBITS_9ANDUP = 9;
|
|
|
|
+
|
|
|
|
+{$ELSEIF SIZEOF(ValReal)=8}
|
|
|
|
+//==================================
|
|
|
|
+// assuming "type ValReal=double;"
|
|
|
|
+//
|
|
|
|
+type
|
|
|
|
+ TValRealRec = packed record
|
|
|
|
+ case byte of
|
|
|
|
+ 0: (
|
|
|
|
+ {$ifndef ENDIAN_BIG}
|
|
|
|
+ raw_lo, raw_hi : longword // little-endian/default
|
|
|
|
+ {$else}
|
|
|
|
+ raw_hi, raw_lo : longword // big-endian
|
|
|
|
+ {$endif}
|
|
|
|
+ );
|
|
|
|
+ 1: (v : double);
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+const
|
|
|
|
+ {$ifndef ENDIAN_BIG}
|
|
|
|
+ // little-endian/default
|
|
|
|
+ C_INFTYP:TValRealRec=(raw_lo:0;raw_hi:$7FF00000); //+INF
|
|
|
|
+ C_INFTYM:TValRealRec=(raw_lo:0;raw_hi:$FFF00000); //-INF
|
|
|
|
+ {$else}
|
|
|
|
+ // big-endian
|
|
|
|
+ C_INFTYP:TValRealRec=(raw_hi:$7FF00000;raw_lo:0); //+INF
|
|
|
|
+ C_INFTYM:TValRealRec=(raw_hi:$FFF00000;raw_lo:0); //-INF
|
|
|
|
+ {$endif}
|
|
|
|
+
|
|
|
|
+ C_MAX_POWER = 319;
|
|
|
|
+
|
|
|
|
+ C_HIGH_EXPBITS_5TO8 = 9;
|
|
|
|
+
|
|
|
|
+{$ELSEIF SIZEOF(ValReal)=4}
|
|
|
|
+//==================================
|
|
|
|
+// assuming "type ValReal=single;"
|
|
|
|
+//
|
|
|
|
+type
|
|
|
|
+ TValRealRec = packed record
|
|
|
|
+ case byte of
|
|
|
|
+ 0: (raw : longword);
|
|
|
|
+ 1: (v : single);
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+const
|
|
|
|
+ C_INFTYP:TValRealRec=(raw:$7F800000); //+INF
|
|
|
|
+ C_INFTYM:TValRealRec=(raw:$FF800000); //-INF
|
|
|
|
+
|
|
|
|
+ C_MAX_POWER = 63;
|
|
|
|
+
|
|
|
|
+{$ELSE}
|
|
|
|
+//==================================
|
|
|
|
+// assuming "ValReal=?"
|
|
|
|
+//
|
|
|
|
+ {$ERROR Unsupported ValReal type}
|
|
|
|
+{$ENDIF}
|
|
|
|
+
|
|
|
|
+//==================================
|
|
|
|
+const
|
|
|
|
+ mul_expbits_0_to_4:packed array[0..31]of ValReal=(
|
|
|
|
+ 1E0, 1E1, 1E2, 1E3,
|
|
|
|
+ 1E4, 1E5, 1E6, 1E7,
|
|
|
|
+ 1E8, 1E9, 1E10, 1E11,
|
|
|
|
+ 1E12, 1E13, 1E14, 1E15,
|
|
|
|
+ 1E16, 1E17, 1E18, 1E19,
|
|
|
|
+ 1E20, 1E21, 1E22, 1E23,
|
|
|
|
+ 1E24, 1E25, 1E26, 1E27,
|
|
|
|
+ 1E28, 1E29, 1E30, 1E31);
|
|
|
|
+
|
|
|
|
+{$IF DECLARED(C_HIGH_EXPBITS_5TO8)}
|
|
|
|
+ mul_expbits_5_to_8:packed array[1..C_HIGH_EXPBITS_5TO8]of ValReal=(
|
|
|
|
+ 1E32, 1E64, 1E96, 1E128,
|
|
|
|
+ 1E160, 1E192, 1E224, 1E256, 1E288
|
|
|
|
+ {$IF DECLARED(C_HIGH_EXPBITS_9ANDUP)},
|
|
|
|
+ 1E320, 1E352, 1E384, 1E416, 1E448, 1E480
|
|
|
|
+ {$ENDIF});
|
|
|
|
+{$ELSE}
|
|
|
|
+ mul_expbits_5_to_8:ValReal=1E32;
|
|
|
|
+{$ENDIF}
|
|
|
|
+
|
|
|
|
+{$IF DECLARED(C_HIGH_EXPBITS_9ANDUP)}
|
|
|
|
+ mul_expbits_9_and_up:packed array[1..C_HIGH_EXPBITS_9ANDUP]of ValReal=(
|
|
|
|
+ 1E512, 1E1024, 1E1536, 1E2048,
|
|
|
|
+ 1E2560, 1E3072, 1E3584, 1E4096,
|
|
|
|
+ 1E4608);
|
|
|
|
+{$ENDIF}
|
|
|
|
+
|
|
|
|
+begin
|
|
|
|
+ if power=0 then mul_by_power10:=x else
|
|
|
|
+ if power<-C_MAX_POWER then mul_by_power10:=0 else
|
|
|
|
+ if power>C_MAX_POWER then
|
|
|
|
+ if x<0 then mul_by_power10:=C_INFTYM.v else
|
|
|
|
+ if x>0 then mul_by_power10:=C_INFTYP.v else mul_by_power10:=0
|
|
|
|
+ else
|
|
|
|
+ if power<0 then
|
|
|
|
+ begin
|
|
|
|
+ power:=-power;
|
|
|
|
+ mul_by_power10:=x/mul_expbits_0_to_4[power and $1F];
|
|
|
|
+ power:=(power shr 5);
|
|
|
|
+ if power=0 then exit;
|
|
|
|
+ {$IF DECLARED(C_HIGH_EXPBITS_5TO8)}
|
|
|
|
+ if power and $F<>0 then
|
|
|
|
+ mul_by_power10:=
|
|
|
|
+ mul_by_power10/mul_expbits_5_to_8[power and $F];
|
|
|
|
+ {$ELSE} // "single", power<>0, so always div
|
|
|
|
+ mul_by_power10:=mul_by_power10/mul_expbits_5_to_8;
|
|
|
|
+ {$ENDIF}
|
|
|
|
+ {$IF DECLARED(C_HIGH_EXPBITS_9ANDUP)}
|
|
|
|
+ power:=(power shr 4);
|
|
|
|
+ if power<>0 then
|
|
|
|
+ mul_by_power10:=
|
|
|
|
+ mul_by_power10/mul_expbits_9_and_up[power];
|
|
|
|
+ {$ENDIF}
|
|
|
|
+ end
|
|
|
|
+ else
|
|
|
|
+ begin
|
|
|
|
+ mul_by_power10:=x*mul_expbits_0_to_4[power and $1F];
|
|
|
|
+ power:=(power shr 5);
|
|
|
|
+ if power=0 then exit;
|
|
|
|
+ {$IF DECLARED(C_HIGH_EXPBITS_5TO8)}
|
|
|
|
+ if power and $F<>0 then
|
|
|
|
+ mul_by_power10:=
|
|
|
|
+ mul_by_power10*mul_expbits_5_to_8[power and $F];
|
|
|
|
+ {$ELSE} // "single", power<>0, so always mul
|
|
|
|
+ mul_by_power10:=mul_by_power10*mul_expbits_5_to_8;
|
|
|
|
+ {$ENDIF}
|
|
|
|
+ {$IF DECLARED(C_HIGH_EXPBITS_9ANDUP)}
|
|
|
|
+ power:=(power shr 4);
|
|
|
|
+ if power<>0 then
|
|
|
|
+ mul_by_power10:=
|
|
|
|
+ mul_by_power10*mul_expbits_9_and_up[power];
|
|
|
|
+ {$ENDIF}
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
Function fpc_Val_Real_ShortStr(const s : shortstring; out Code : ValSInt): ValReal; [public, alias:'FPC_VAL_REAL_SHORTSTR']; compilerproc;
|
|
Function fpc_Val_Real_ShortStr(const s : shortstring; out Code : ValSInt): ValReal; [public, alias:'FPC_VAL_REAL_SHORTSTR']; compilerproc;
|
|
var
|
|
var
|
|
- hd,
|
|
|
|
- esign,sign : valreal;
|
|
|
|
|
|
+ sign : valreal;
|
|
|
|
+ esign,
|
|
exponent,
|
|
exponent,
|
|
decpoint,i : SizeInt;
|
|
decpoint,i : SizeInt;
|
|
flags : byte;
|
|
flags : byte;
|
|
@@ -1253,28 +1465,7 @@ begin
|
|
fpc_Val_Real_ShortStr:=fpc_Val_Real_ShortStr*sign;
|
|
fpc_Val_Real_ShortStr:=fpc_Val_Real_ShortStr*sign;
|
|
|
|
|
|
{ Calculate Exponent }
|
|
{ Calculate Exponent }
|
|
- hd:=1.0;
|
|
|
|
- { the magnitude range maximum (normal) is lower in absolute value than the }
|
|
|
|
- { the magnitude range minimum (denormal). E.g. an extended value can go }
|
|
|
|
- { up to 1E4932, but "down" to 1E-4951. So make sure that we don't try to }
|
|
|
|
- { calculate 1E4951 as factor, since that would overflow and result in 0. }
|
|
|
|
- if (exponent>valmaxexpnorm-2) then
|
|
|
|
- begin
|
|
|
|
- for i:=1 to valmaxexpnorm-2 do
|
|
|
|
- hd:=hd*10.0;
|
|
|
|
- if esign>0 then
|
|
|
|
- fpc_Val_Real_ShortStr:=fpc_Val_Real_ShortStr*hd
|
|
|
|
- else
|
|
|
|
- fpc_Val_Real_ShortStr:=fpc_Val_Real_ShortStr/hd;
|
|
|
|
- dec(exponent,valmaxexpnorm-2);
|
|
|
|
- hd:=1.0;
|
|
|
|
- end;
|
|
|
|
- for i:=1 to exponent do
|
|
|
|
- hd:=hd*10.0;
|
|
|
|
- if esign>0 then
|
|
|
|
- fpc_Val_Real_ShortStr:=fpc_Val_Real_ShortStr*hd
|
|
|
|
- else
|
|
|
|
- fpc_Val_Real_ShortStr:=fpc_Val_Real_ShortStr/hd;
|
|
|
|
|
|
+fpc_Val_Real_ShortStr:=mul_by_power10(fpc_Val_Real_ShortStr,exponent*esign);
|
|
|
|
|
|
{ Not all characters are read ? }
|
|
{ Not all characters are read ? }
|
|
if length(s)>=code then
|
|
if length(s)>=code then
|