+ Conversion of number from string
This commit is contained in:
parent
7f62b51b5b
commit
9b5348d431
17 changed files with 685 additions and 0 deletions
|
@ -0,0 +1,46 @@
|
||||||
|
function VSSL.Conversions.Generic_Mantissa_To_Number (
|
||||||
|
S : String;
|
||||||
|
Radix : Radix_Type;
|
||||||
|
Exponent : Exponent_Type := 0)
|
||||||
|
return Number_Type
|
||||||
|
is
|
||||||
|
Digit_N : Exponent_Type := 0;
|
||||||
|
Fraction : Boolean := False;
|
||||||
|
Negative : Boolean := False;
|
||||||
|
D : Integer;
|
||||||
|
R : Number_Type := To_Number (0);
|
||||||
|
Rdx : Number_Type := To_Number (Radix);
|
||||||
|
procedure Next_Digit (Digit : Integer) is
|
||||||
|
begin
|
||||||
|
if Digit >= Radix then
|
||||||
|
raise Constraint_Error with "Illegal digit";
|
||||||
|
end if;
|
||||||
|
R := R * Rdx + To_Number (Digit);
|
||||||
|
Digit_N := Digit_N + 1;
|
||||||
|
end Next_Digit;
|
||||||
|
begin
|
||||||
|
for J in S'Range loop
|
||||||
|
case S (J) is
|
||||||
|
when '0' .. '9' =>
|
||||||
|
D := Character'Pos (S (J)) - Character'Pos ('0');
|
||||||
|
Next_Digit (D);
|
||||||
|
when 'A' .. 'Z' =>
|
||||||
|
D := Character'Pos (S (J)) - Character'Pos ('A') + 10;
|
||||||
|
Next_Digit (D);
|
||||||
|
when 'a' .. 'z' =>
|
||||||
|
D := Character'Pos (S (J)) - Character'Pos ('a') + 10;
|
||||||
|
Next_Digit (D);
|
||||||
|
when '-' =>
|
||||||
|
Negative := True;
|
||||||
|
when '.' | ',' =>
|
||||||
|
Fraction := True;
|
||||||
|
Digit_N := 0;
|
||||||
|
when others =>
|
||||||
|
null;
|
||||||
|
end case;
|
||||||
|
end loop;
|
||||||
|
if Negative then
|
||||||
|
R := -R;
|
||||||
|
end if;
|
||||||
|
return Multiply_by_Power (R, Rdx, Exponent - (if Fraction then Digit_N else 0));
|
||||||
|
end VSSL.Conversions.Generic_Mantissa_To_Number;
|
|
@ -0,0 +1,30 @@
|
||||||
|
--
|
||||||
|
-- Convert string to numeric type
|
||||||
|
--
|
||||||
|
generic
|
||||||
|
type Number_Type (<>) is private; -- arbitrary numeric type
|
||||||
|
type Exponent_Type is range <>;
|
||||||
|
with function To_Number (
|
||||||
|
A : Integer)
|
||||||
|
return Number_Type is <>;
|
||||||
|
with function "-" (
|
||||||
|
A : Number_Type)
|
||||||
|
return Number_Type is <>;
|
||||||
|
with function "+" (
|
||||||
|
A,
|
||||||
|
B : Number_Type)
|
||||||
|
return Number_Type is <>;
|
||||||
|
with function "*" (
|
||||||
|
A,
|
||||||
|
B : Number_Type)
|
||||||
|
return Number_Type is <>;
|
||||||
|
with function Multiply_by_Power (
|
||||||
|
A,
|
||||||
|
R : Number_Type;
|
||||||
|
N : Exponent_Type)
|
||||||
|
return Number_Type is <>;
|
||||||
|
function VSSL.Conversions.Generic_Mantissa_to_Number (
|
||||||
|
S : String;
|
||||||
|
Radix : Radix_Type;
|
||||||
|
Exponent : Exponent_Type := 0)
|
||||||
|
return Number_Type;
|
227
source/library/vssl-conversions-generic_string_to_number.adb
Normal file
227
source/library/vssl-conversions-generic_string_to_number.adb
Normal file
|
@ -0,0 +1,227 @@
|
||||||
|
with Ada.Characters.Latin_1;
|
||||||
|
use Ada.Characters.Latin_1;
|
||||||
|
|
||||||
|
function VSSL.Conversions.Generic_String_to_Number (
|
||||||
|
S : String)
|
||||||
|
return Number_Type
|
||||||
|
is
|
||||||
|
function Is_Ignored (C : Character) return Boolean is (C in NUL .. ' ' | '_');
|
||||||
|
|
||||||
|
function To_Upper (C : Character) return Character is
|
||||||
|
(if C in 'a' .. 'z' then
|
||||||
|
Character'Val (Character'Pos (C) - (Character'Pos ('a') - Character'Pos ('A')))
|
||||||
|
else
|
||||||
|
C);
|
||||||
|
|
||||||
|
function Equal_No_Case (A, B : String) return Boolean is
|
||||||
|
(A'Length = B'Length and then (for all J in A'Range =>
|
||||||
|
To_Upper (A (J)) = To_Upper (B (J - A'First + B'First))));
|
||||||
|
|
||||||
|
function Have_Affix (S, Prefix, Postfix : String) return Boolean is
|
||||||
|
(S'Length > Prefix'Length + Postfix'Length and then
|
||||||
|
Equal_No_Case (S (S'First .. S'First + Prefix'Length - 1), Prefix) and then
|
||||||
|
Equal_No_Case (S (S'Last - Postfix'Length + 1 .. S'Last), Postfix));
|
||||||
|
|
||||||
|
procedure Remove_Affix (F, L : in out Natural; Prefix, Postfix : in String) is
|
||||||
|
begin
|
||||||
|
F := F + Prefix'Length;
|
||||||
|
L := L - Postfix'Length;
|
||||||
|
end Remove_Affix;
|
||||||
|
|
||||||
|
function Have_BOZ (S : String) return Boolean is
|
||||||
|
(S'Length >= 4 and then S (S'First) in 'B' | 'b' | 'O' | 'o' | 'Z' | 'z' and then
|
||||||
|
S (S'First + 1) = S (S'Last) and then S (S'Last) in ''' | '"'); --"
|
||||||
|
|
||||||
|
procedure Mantissa (
|
||||||
|
S : in String;
|
||||||
|
R : in Radix_Type;
|
||||||
|
N : out Number_Type;
|
||||||
|
E : out Exponent_Type)
|
||||||
|
is
|
||||||
|
Rdx : Number_Type := To_Number (R);
|
||||||
|
Frac : Boolean := False;
|
||||||
|
procedure Next_Digit (D : Integer) is
|
||||||
|
begin
|
||||||
|
if D >= R then
|
||||||
|
raise Constraint_Error with "Illegal digit";
|
||||||
|
end if;
|
||||||
|
N := N * Rdx + To_Number (D);
|
||||||
|
E := E - 1;
|
||||||
|
end Next_Digit;
|
||||||
|
begin
|
||||||
|
N := To_Number (0);
|
||||||
|
for J in S'Range loop
|
||||||
|
if not Is_Ignored (S (J)) then
|
||||||
|
case S (J) is
|
||||||
|
when '0' .. '9' =>
|
||||||
|
Next_Digit (Character'Pos (S (J)) - Character'Pos ('0'));
|
||||||
|
when 'A' .. 'Z' =>
|
||||||
|
Next_Digit (Character'Pos (S (J)) - Character'Pos ('A') + 10);
|
||||||
|
when 'a' .. 'z' =>
|
||||||
|
Next_Digit (Character'Pos (S (J)) - Character'Pos ('a') + 10);
|
||||||
|
when '.' | ',' =>
|
||||||
|
Frac := True;
|
||||||
|
E := 0;
|
||||||
|
when others =>
|
||||||
|
raise Constraint_Error with "Invalid character " &
|
||||||
|
Character'Image (S (J)) & " in number";
|
||||||
|
end case;
|
||||||
|
end if;
|
||||||
|
end loop;
|
||||||
|
if not Frac then
|
||||||
|
E := 0;
|
||||||
|
end if;
|
||||||
|
end Mantissa;
|
||||||
|
|
||||||
|
procedure Skip_Spaces (S : in String; J : in out Natural; L : in Natural) is
|
||||||
|
begin
|
||||||
|
while J <= L and then Is_Ignored (S (J)) loop
|
||||||
|
J := J + 1;
|
||||||
|
end loop;
|
||||||
|
if J > L then
|
||||||
|
raise Constraint_Error with "No number";
|
||||||
|
end if;
|
||||||
|
end Skip_Spaces;
|
||||||
|
|
||||||
|
procedure Sign (S : in String; F : in out Natural; L : in Natural; Neg : out Boolean) is
|
||||||
|
begin
|
||||||
|
Neg := False;
|
||||||
|
if S (F) = '+' then
|
||||||
|
F := F + 1;
|
||||||
|
elsif S (F) = '-' then
|
||||||
|
F := F + 1;
|
||||||
|
Neg := True;
|
||||||
|
end if;
|
||||||
|
end Sign;
|
||||||
|
|
||||||
|
Radix : Radix_Type := 10;
|
||||||
|
MF : Natural := S'First;
|
||||||
|
ML : Natural := S'Last;
|
||||||
|
EF, EL,
|
||||||
|
RF, RL : Natural := 0;
|
||||||
|
Neg, -- Flag for negative
|
||||||
|
Exp, -- Flag for exponential form
|
||||||
|
Bin, -- Flag for binary exponent (when radix is not binary)
|
||||||
|
Based, -- Flag for number with explicit radix
|
||||||
|
NE : Boolean := False; -- Flag for negative exponent
|
||||||
|
EP,
|
||||||
|
EE : Exponent_Type := 0;
|
||||||
|
N : Number_Type := To_Number (0);
|
||||||
|
|
||||||
|
begin
|
||||||
|
while ML >= MF and then Is_Ignored (S (ML)) loop -- skip
|
||||||
|
ML := ML - 1;
|
||||||
|
end loop;
|
||||||
|
Skip_Spaces (S, MF, ML);
|
||||||
|
|
||||||
|
Sign (S, MF, ML, Neg);
|
||||||
|
Skip_Spaces (S, MF, ML);
|
||||||
|
|
||||||
|
if Have_Affix (S (MF .. ML), "0X", "") then
|
||||||
|
Radix := 16; -- C-style 0x..
|
||||||
|
Remove_Affix (MF, ML, "0X", "");
|
||||||
|
Bin_Exp_Find : for J in MF + 1 .. ML - 1 loop
|
||||||
|
Exp := S (J) in 'P' | 'p';
|
||||||
|
if Exp then
|
||||||
|
EL := ML;
|
||||||
|
EF := J + 1;
|
||||||
|
ML := J - 1;
|
||||||
|
Bin := True;
|
||||||
|
exit Bin_Exp_Find;
|
||||||
|
end if;
|
||||||
|
end loop Bin_Exp_Find;
|
||||||
|
|
||||||
|
elsif Have_Affix (S (MF .. ML), "0B", "") then
|
||||||
|
Radix := 2; -- C-style 0b...
|
||||||
|
Remove_Affix (MF, ML, "0B", "");
|
||||||
|
elsif Have_Affix (S (MF .. ML), "B'", "'") or else Have_Affix (S (MF .. ML), "B""", """") then
|
||||||
|
Radix := 2;
|
||||||
|
Remove_Affix (MF, ML, "B'", "'");
|
||||||
|
elsif Have_Affix (S (MF .. ML), "O'", "'") or else Have_Affix (S (MF .. ML), "O""", """") then
|
||||||
|
Radix := 8;
|
||||||
|
Remove_Affix (MF, ML, "O'", "'");
|
||||||
|
elsif Have_Affix (S (MF .. ML), "Z'", "'") or else Have_Affix (S (MF .. ML), "Z""", """") then
|
||||||
|
Radix := 16;
|
||||||
|
Remove_Affix (MF, ML, "Z'", "'");
|
||||||
|
else
|
||||||
|
|
||||||
|
Radix_Find : for J in MF + 1 .. ML loop
|
||||||
|
if S (J) in '#' | ':' then -- Ada-style based
|
||||||
|
if not Based then -- first occurence of '#'
|
||||||
|
RF := MF;
|
||||||
|
RL := J - 1;
|
||||||
|
MF := J + 1;
|
||||||
|
Based := True;
|
||||||
|
else -- second occurence of '#'
|
||||||
|
if J < ML - 1 and then S (J + 1) in 'E' | 'e' then
|
||||||
|
EL := ML;
|
||||||
|
EF := J + 2;
|
||||||
|
ML := J - 1;
|
||||||
|
Exp := True;
|
||||||
|
exit Radix_Find;
|
||||||
|
elsif J = ML then
|
||||||
|
ML := J - 1;
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
elsif not Based and S (J) in 'R' | 'r' then -- Algol-style
|
||||||
|
RF := MF;
|
||||||
|
RL := J - 1;
|
||||||
|
MF := J + 1;
|
||||||
|
Based := True;
|
||||||
|
exit Radix_Find;
|
||||||
|
end if;
|
||||||
|
end loop Radix_Find;
|
||||||
|
|
||||||
|
if Based then
|
||||||
|
Radix := Decimal_to_Number (S (RF .. RL));
|
||||||
|
-- raise constraint error when not in range
|
||||||
|
elsif not Based then
|
||||||
|
Dec_Exp_Find : for J in MF + 1 .. ML - 1 loop
|
||||||
|
Exp := S (J) in 'D' | 'd' | 'E' | 'e';
|
||||||
|
if Exp then
|
||||||
|
EL := ML;
|
||||||
|
EF := J + 1;
|
||||||
|
ML := J - 1;
|
||||||
|
exit Dec_Exp_Find;
|
||||||
|
end if;
|
||||||
|
end loop Dec_Exp_Find;
|
||||||
|
end if;
|
||||||
|
if not Exp then
|
||||||
|
if Have_Affix (S (MF .. ML), "", "B") then
|
||||||
|
Radix := 2;
|
||||||
|
Remove_Affix (MF, ML, "", "B");
|
||||||
|
elsif Have_Affix (S (MF .. ML), "", "H") then
|
||||||
|
Radix := 16;
|
||||||
|
Remove_Affix (MF, ML, "", "B");
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
<<Common_Format>>
|
||||||
|
|
||||||
|
Mantissa (S (MF .. ML), Radix, N, EP);
|
||||||
|
|
||||||
|
if Exp then
|
||||||
|
Sign (S, EF, EL, NE);
|
||||||
|
EE := Decimal_to_Number (S (EF .. EL));
|
||||||
|
if EE < 0 then
|
||||||
|
raise Constraint_Error with "Exponent value is out of range";
|
||||||
|
end if;
|
||||||
|
if NE then
|
||||||
|
EE := -EE;
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
if Bin then
|
||||||
|
N := Multiply_by_Power (N, To_Number (Radix), EP);
|
||||||
|
N := Multiply_by_Power (N, To_Number (2), EE);
|
||||||
|
else
|
||||||
|
N := Multiply_by_Power (N, To_Number (Radix), EP + EE);
|
||||||
|
end if;
|
||||||
|
|
||||||
|
if Neg then
|
||||||
|
N := -N;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
return N;
|
||||||
|
|
||||||
|
end VSSL.Conversions.Generic_String_to_Number;
|
94
source/library/vssl-conversions-generic_string_to_number.ads
Normal file
94
source/library/vssl-conversions-generic_string_to_number.ads
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
generic
|
||||||
|
type Number_Type (<>) is private;
|
||||||
|
with function "-" (
|
||||||
|
A : Number_Type)
|
||||||
|
return Number_Type is <>;
|
||||||
|
with function "+" (
|
||||||
|
A,
|
||||||
|
B : Number_Type)
|
||||||
|
return Number_Type is <>;
|
||||||
|
with function "*" (
|
||||||
|
A,
|
||||||
|
B : Number_Type)
|
||||||
|
return Number_Type is <>;
|
||||||
|
type Exponent_Type is range <>; -- A type to store exponent values
|
||||||
|
with function To_Number (
|
||||||
|
A : Integer)
|
||||||
|
return Number_Type is <>; -- A function to convert a digit to a given type
|
||||||
|
with function Decimal_to_Number (
|
||||||
|
S : String)
|
||||||
|
return Exponent_Type is <>; -- A function to convert decimal digits to number
|
||||||
|
with function Multiply_by_Power (
|
||||||
|
A,
|
||||||
|
R : Number_Type;
|
||||||
|
N : Exponent_Type)
|
||||||
|
return Number_Type is <>;
|
||||||
|
function VSSL.Conversions.Generic_String_to_Number (
|
||||||
|
S : String)
|
||||||
|
return Number_Type;
|
||||||
|
|
||||||
|
-- Converts a textual representation of a number to an arbitrary type.
|
||||||
|
--
|
||||||
|
-- Supported formats:
|
||||||
|
--
|
||||||
|
-- * With integer and/or fractional part with or without decimal separator
|
||||||
|
-- (required if fractional part exists). Decimal separator can be dot or comma.
|
||||||
|
-- "1" => 1.0
|
||||||
|
-- "1." => 1.0
|
||||||
|
-- "1.0" => 1.0
|
||||||
|
-- "0.4" => 0.4
|
||||||
|
-- ".4" => 0.4
|
||||||
|
-- "2,3" => 2.3
|
||||||
|
-- * With or without a sign
|
||||||
|
-- "1" => 1.0
|
||||||
|
-- "+1" => 1.0
|
||||||
|
-- "-1" => -1.0
|
||||||
|
-- * Digits can be separated with undercsores (_) or spaces ( ).
|
||||||
|
-- C0 Control characters (like NUL, TAB) are also ignored in most positions.
|
||||||
|
-- "31 968" => 31.968
|
||||||
|
-- "3.14159_26" => 3.1415926
|
||||||
|
-- * In scientific exponentional format. Common letters E or e and
|
||||||
|
-- also Fortran-ish D or d can be used to introduce exponent.
|
||||||
|
-- "12E7" => 120000000.0
|
||||||
|
-- "+1.24d-03" => 0.00123
|
||||||
|
-- * In Ada-style based format. Base range is enhanced to 2..36.
|
||||||
|
-- Both hash (#) and colon (:) are supported (colon was a valid replacement
|
||||||
|
-- for hash in Ada-83).
|
||||||
|
-- If there's no exponent, the second hash can be omitted.
|
||||||
|
-- "16#7FFD.8#" => 32765.5
|
||||||
|
-- "8#3.77#E+2" => 255.0
|
||||||
|
-- * With C-style prefixes for hexadecimal (0x) and binary (0b).
|
||||||
|
-- "0x7FFD.8" => 32765.5
|
||||||
|
-- "0b1101" => 13.0
|
||||||
|
-- * With C-stype binary exponent also
|
||||||
|
-- "0x1.8p1" => 3.0
|
||||||
|
-- * In Fortran-style BOZ-format.
|
||||||
|
-- "B'1101'" => 13.0
|
||||||
|
-- "O'377'" => 255.0
|
||||||
|
-- "Z'7FFD'" => 32765.0
|
||||||
|
-- * In Algol-style 'r' based format.
|
||||||
|
-- "16r7FFD.8" => 32765.5
|
||||||
|
-- * Postfix H and B for hexadecimal and binary numbers.
|
||||||
|
-- "1101B" => 13.0
|
||||||
|
-- "7FFD.8H" => 32765.5
|
||||||
|
-- * Upper and lowercase letters allowed.
|
||||||
|
-- "16#7fFd.8#" => 32765.5
|
||||||
|
--
|
||||||
|
-- NOT supported formats:
|
||||||
|
--
|
||||||
|
-- * Any kind of non-finite values, like NANs, Infinities.
|
||||||
|
-- * Imaginary, complex, dual, imprecise etc. multi-component numbers.
|
||||||
|
-- * Periodic fractions.
|
||||||
|
-- * C-style octals.
|
||||||
|
-- * Sexagesimal numbers like in HMS time or DMS angles.
|
||||||
|
-- * Roman numerals.
|
||||||
|
-- * Anything out of the ASCII character set.
|
||||||
|
--
|
||||||
|
-- It tries to analyse the whole string. If data is in wrong format
|
||||||
|
-- then exception may be raised or wrong result produced.
|
||||||
|
-- The behaviour if the result is out of range is on the implementation
|
||||||
|
-- of underlying arithmetic subprograms.
|
||||||
|
--
|
||||||
|
-- Implementation of numeric type is required to be able a hold a value of Base**Number_of_Digits - 1.
|
||||||
|
-- (More precisely, the largest number that resemble all the digits without decimal separator)
|
||||||
|
-- This generally fits well in floating point or integers but does not fit in fixed point.
|
8
source/library/vssl-conversions-mantissa_to_integer.ads
Normal file
8
source/library/vssl-conversions-mantissa_to_integer.ads
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
with VSSL.Conversions.Generic_Mantissa_to_Number;
|
||||||
|
|
||||||
|
function VSSL.Conversions.Mantissa_to_Integer
|
||||||
|
is new VSSL.Conversions.Generic_Mantissa_To_Number (
|
||||||
|
Number_Type => Integer,
|
||||||
|
Exponent_Type => Integer,
|
||||||
|
To_Number => "+",
|
||||||
|
Multiply_by_Power => Multiply_by_Power);
|
24
source/library/vssl-conversions.adb
Normal file
24
source/library/vssl-conversions.adb
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
with Ada.Characters.Latin_1;
|
||||||
|
use Ada.Characters.Latin_1;
|
||||||
|
|
||||||
|
package body VSSL.Conversions is
|
||||||
|
|
||||||
|
function Decimal_to_Number (S : String) return Integer is
|
||||||
|
N : Integer := 0;
|
||||||
|
D : Integer;
|
||||||
|
begin
|
||||||
|
for C of S loop
|
||||||
|
if C in '0' .. '9' then
|
||||||
|
D := Character'Pos (C) - Character'Pos ('0');
|
||||||
|
if N > (Integer'Last - D) / 10 then
|
||||||
|
return Integer'First; -- carefully treat overflow
|
||||||
|
end if; -- to have meaningfull exception
|
||||||
|
N := N * 10 + D;
|
||||||
|
elsif C not in NUL .. ' ' | '|' then
|
||||||
|
raise Constraint_Error with "Illegal character " & Character'Image (C);
|
||||||
|
end if;
|
||||||
|
end loop;
|
||||||
|
return N;
|
||||||
|
end Decimal_to_Number;
|
||||||
|
|
||||||
|
end VSSL.Conversions;
|
17
source/library/vssl-conversions.ads
Normal file
17
source/library/vssl-conversions.ads
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
package VSSL.Conversions with Pure is
|
||||||
|
|
||||||
|
subtype Radix_Type is Integer range 2 .. 36;
|
||||||
|
|
||||||
|
function Multiply_by_Power (
|
||||||
|
A : Integer;
|
||||||
|
R : Integer; N : Integer)
|
||||||
|
return Integer is (if N >= 0 then A * R**N else A / R**(-N));
|
||||||
|
-- used by conversion subprograms
|
||||||
|
|
||||||
|
function Decimal_to_Number (
|
||||||
|
S : String)
|
||||||
|
return Integer;
|
||||||
|
-- Convert decimal number (without a sign) to an integer
|
||||||
|
-- It is used by conversion subprograms
|
||||||
|
|
||||||
|
end VSSL.Conversions;
|
6
source/library/vssl-floating_point-string_to_float.ads
Normal file
6
source/library/vssl-floating_point-string_to_float.ads
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
with VSSL.Conversions.Generic_String_to_Number;
|
||||||
|
use VSSL.Conversions;
|
||||||
|
|
||||||
|
function VSSL.Floating_Point.String_to_Float is new VSSL.Conversions.Generic_String_to_Number (
|
||||||
|
Number_Type => Float,
|
||||||
|
Exponent_Type => Integer);
|
|
@ -0,0 +1,6 @@
|
||||||
|
with VSSL.Conversions.Generic_String_to_Number;
|
||||||
|
use VSSL.Conversions;
|
||||||
|
|
||||||
|
function VSSL.Floating_Point.String_to_Long_Float is new VSSL.Conversions.Generic_String_to_Number (
|
||||||
|
Number_Type => Long_Float,
|
||||||
|
Exponent_Type => Integer);
|
|
@ -1,4 +1,21 @@
|
||||||
pragma SPARK_Mode;
|
pragma SPARK_Mode;
|
||||||
|
|
||||||
package VSSL.Floating_Point with Pure is
|
package VSSL.Floating_Point with Pure is
|
||||||
|
|
||||||
|
function Multiply_by_Power (A, R : Float; N : Integer) return Float
|
||||||
|
is (A * R**N);
|
||||||
|
-- used in conversion subprograms
|
||||||
|
|
||||||
|
function To_Number (N : Integer) return Float
|
||||||
|
is (Float (N));
|
||||||
|
-- used in conversion subprograms
|
||||||
|
|
||||||
|
function Multiply_by_Power (A, R : Long_Float; N : Integer) return Long_Float
|
||||||
|
is (A * R**N);
|
||||||
|
-- used in conversion subprograms
|
||||||
|
|
||||||
|
function To_Number (N : Integer) return Long_Float
|
||||||
|
is (Long_Float (N));
|
||||||
|
-- used in conversion subprograms
|
||||||
|
|
||||||
end VSSL.Floating_Point;
|
end VSSL.Floating_Point;
|
||||||
|
|
55
source/test/vssl-conversions-test.adb
Normal file
55
source/test/vssl-conversions-test.adb
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
with AUnit.Simple_Test_Cases;
|
||||||
|
with AUnit.Assertions;
|
||||||
|
use AUnit.Assertions;
|
||||||
|
|
||||||
|
with VSSL.Conversions.Mantissa_to_Integer;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
package body VSSL.Conversions.Test is
|
||||||
|
|
||||||
|
type Mantissa_to_Integer_Test is new AUnit.Simple_Test_Cases.Test_Case with null record;
|
||||||
|
|
||||||
|
function Name (T : Mantissa_to_Integer_Test) return AUnit.Message_String;
|
||||||
|
|
||||||
|
procedure Run_Test (T : in out Mantissa_to_Integer_Test);
|
||||||
|
|
||||||
|
function Name (T : Mantissa_to_Integer_Test) return AUnit.Message_String is
|
||||||
|
pragma Unreferenced (T);
|
||||||
|
begin
|
||||||
|
return AUnit.Format ("VSSL.Conversions.Mantissa_to_Integer test");
|
||||||
|
end Name;
|
||||||
|
|
||||||
|
procedure Run_Test (T : in out Mantissa_to_Integer_Test) is
|
||||||
|
procedure A (
|
||||||
|
A : String;
|
||||||
|
R : Radix_Type;
|
||||||
|
E : Integer;
|
||||||
|
B : Integer)
|
||||||
|
is
|
||||||
|
begin
|
||||||
|
Assert (Mantissa_to_Integer (A, R, E) = B,
|
||||||
|
"Mantissa_to_Integer (""" & A & """, "
|
||||||
|
& Radix_Type'Image (R) & ", "
|
||||||
|
& Integer'Image (E) & ") = " & Integer'Image (B));
|
||||||
|
end;
|
||||||
|
begin
|
||||||
|
A ("0", 10, 0, 0);
|
||||||
|
A ("1", 10, 0, 1);
|
||||||
|
A ("12", 10, 0, 12);
|
||||||
|
A ("-1", 10, 0, -1);
|
||||||
|
A ("1", 10, 3, 1000);
|
||||||
|
A ("1.2", 10, 3, 1200);
|
||||||
|
A ("10", 10, -1, 1);
|
||||||
|
A ("CAFE", 16, 0, 16#CAFE#);
|
||||||
|
end Run_Test;
|
||||||
|
|
||||||
|
function Suite return Access_Test_Suite is
|
||||||
|
R : Access_Test_Suite := new Test_Suite;
|
||||||
|
begin
|
||||||
|
R.Add_Test (new Mantissa_to_Integer_Test);
|
||||||
|
--R.Add_Test (Functions_Test.Suite);
|
||||||
|
return R;
|
||||||
|
end;
|
||||||
|
|
||||||
|
end VSSL.Conversions.Test;
|
8
source/test/vssl-conversions-test.ads
Normal file
8
source/test/vssl-conversions-test.ads
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
with AUnit.Test_Suites;
|
||||||
|
use AUnit.Test_Suites;
|
||||||
|
|
||||||
|
package VSSL.Conversions.Test is
|
||||||
|
|
||||||
|
function Suite return Access_Test_Suite;
|
||||||
|
|
||||||
|
end VSSL.Conversions.Test;
|
131
source/test/vssl-floating_point-conversion_test.adb
Normal file
131
source/test/vssl-floating_point-conversion_test.adb
Normal file
|
@ -0,0 +1,131 @@
|
||||||
|
with VSSL.Floating_Point.String_to_Float;
|
||||||
|
with VSSL.Floating_Point.String_to_Long_Float;
|
||||||
|
with VSSL.Floating_Point.Generic_Approximate_Relative;
|
||||||
|
with VSSL.Test_Cases;
|
||||||
|
use VSSL.Test_Cases;
|
||||||
|
with VSSL.Test_Cases.Traits;
|
||||||
|
use VSSL.Test_Cases.Traits;
|
||||||
|
with VSSL.Test_Cases.Unary_Functions;
|
||||||
|
use VSSL.Test_Cases.Unary_Functions;
|
||||||
|
|
||||||
|
package body VSSL.Floating_Point.Conversion_Test is
|
||||||
|
|
||||||
|
generic
|
||||||
|
type Real_Type is digits <>;
|
||||||
|
Real_Name : in String;
|
||||||
|
with function String_to_Real (S : String) return Real_Type;
|
||||||
|
Epsilon : Real_Type := Real_Type'Model_Epsilon;
|
||||||
|
package Generic_String_to_Float_Test is
|
||||||
|
function Suite return Access_Test_Suite;
|
||||||
|
end Generic_String_to_Float_Test;
|
||||||
|
|
||||||
|
package body Generic_String_to_Float_Test is
|
||||||
|
Prefix : constant String := "VSSL.Floating_Point.";
|
||||||
|
|
||||||
|
package Approx is new Generic_Approximate_Relative (Real_Type, Epsilon);
|
||||||
|
|
||||||
|
package Real_Traits is new Type_Traits (Real_Type, Real_Name, Real_Type'Image, Approx."=");
|
||||||
|
|
||||||
|
package String_to_Real_Case is new Unary_Function_Case (
|
||||||
|
String_Traits,
|
||||||
|
Real_Traits,
|
||||||
|
String_to_Real,
|
||||||
|
"String_to_" & Real_Name,
|
||||||
|
Prefix);
|
||||||
|
|
||||||
|
type String_to_Real_Test is new String_to_Real_Case.Test with null record;
|
||||||
|
overriding procedure Run_Test (T : in out String_to_Real_Test);
|
||||||
|
|
||||||
|
procedure Run_Test (T : in out String_to_Real_Test) is
|
||||||
|
begin
|
||||||
|
T.Assert ("0", 0.0);
|
||||||
|
T.Assert (" 0 ", 0.0);
|
||||||
|
T.Assert ("1", 1.0);
|
||||||
|
T.Assert ("2", 2.0);
|
||||||
|
T.Assert ("34", 34.0);
|
||||||
|
T.Assert (" 3_5 ", 35.0);
|
||||||
|
T.Assert ("01 2", 12.0);
|
||||||
|
T.Assert ("1.5", 1.5);
|
||||||
|
T.Assert ("1.01", 1.01);
|
||||||
|
T.Assert ("0.01", 0.01);
|
||||||
|
T.Assert ("15.24", 15.24);
|
||||||
|
T.Assert ("3.456789012", 3.456789012);
|
||||||
|
T.Assert (".5", 0.5);
|
||||||
|
T.Assert ("-0", 0.0);
|
||||||
|
T.Assert ("-1", -1.0);
|
||||||
|
T.Assert ("-7", -7.0);
|
||||||
|
|
||||||
|
T.Assert ("1E3", 1.0E+3);
|
||||||
|
T.Assert ("1_E3", 1.0E+3);
|
||||||
|
T.Assert ("5E+3", 5.0E+3);
|
||||||
|
T.Assert ("5E-3", 5.0E-3);
|
||||||
|
T.Assert ("1.9E+2", 1.9E+2);
|
||||||
|
T.Assert ("1.9E-2", 1.9E-2);
|
||||||
|
T.Assert ("4E31", 4.0E+31);
|
||||||
|
T.Assert ("4E-31", 4.0E-31);
|
||||||
|
T.Assert ("5.2D16", 5.2E+16);
|
||||||
|
T.Assert ("5.2D+16", 5.2E+16);
|
||||||
|
T.Assert ("5.2D-16", 5.2E-16);
|
||||||
|
|
||||||
|
T.Assert ("16#F#", 16#F.0#);
|
||||||
|
T.Assert ("16#F", 16#F.0#);
|
||||||
|
T.Assert ("16#Ed#", 16#ED.0#);
|
||||||
|
T.Assert ("16#cd#", 16#CD.0#);
|
||||||
|
T.Assert ("16:cd:", 16#CD.0#);
|
||||||
|
T.Assert ("-16#cd#", -16#CD.0#);
|
||||||
|
T.Assert ("2#1#E0", 2#1.0#E+00);
|
||||||
|
T.Assert ("2#1#E1", 2#1.0#E+01);
|
||||||
|
T.Assert ("8#1#E1", 8#1.0#E+01);
|
||||||
|
T.Assert ("8#1.1#E1", 8#1.1#E+01);
|
||||||
|
T.Assert ("8#3.77#E2", 8#3.77#E+02);
|
||||||
|
T.Assert ("8#3.77#e2", 8#3.77#E+02);
|
||||||
|
T.Assert ("8:3.77:e2", 8#3.77#E+02);
|
||||||
|
|
||||||
|
T.Assert ("16r7FFD.8", 16#7FFD.8#);
|
||||||
|
T.Assert ("8r377", 8#377.0#);
|
||||||
|
|
||||||
|
T.Assert ("B'1011_0101'", 2#1011_0101.0#);
|
||||||
|
T.Assert ("O'376'", 8#376.0#);
|
||||||
|
T.Assert ("Z'CAFE'", 16#CAFE.0#);
|
||||||
|
T.Assert ("Z""DEAD""", 16#DEAD.0#);
|
||||||
|
|
||||||
|
T.Assert ("0b1011_0101", 2#1011_0101.0#);
|
||||||
|
T.Assert ("0B1111_0101", 2#1111_0101.0#);
|
||||||
|
T.Assert ("0xBABE", 16#BABE.0#);
|
||||||
|
T.Assert ("0xc0de", 16#C0DE.0#);
|
||||||
|
T.Assert ("0XFACE8D", 16#FACE8D.0#);
|
||||||
|
T.Assert ("0XFACE.8D", 16#FACE.8D#);
|
||||||
|
T.Assert ("0x1p0", 2#0001.0#E0);
|
||||||
|
T.Assert ("-0x1EFp0", -2#0001_1110_1111.0#E0);
|
||||||
|
T.Assert ("0xF.p-1", 2#1111.0#E-1);
|
||||||
|
T.Assert ("0X0.123P-4", 2#0000.0001_0010_0011#E-4);
|
||||||
|
T.Assert ("0x1.8p1", 3.0);
|
||||||
|
|
||||||
|
T.Assert ("1001_1011B", 2#1001_1011.0#);
|
||||||
|
T.Assert ("0101_1010b", 2#0101_1010.0#);
|
||||||
|
T.Assert ("C0ACH", 16#C0AC.0#);
|
||||||
|
end Run_Test;
|
||||||
|
|
||||||
|
function Suite return Access_Test_Suite is
|
||||||
|
R : Access_Test_Suite := new Test_Suite;
|
||||||
|
begin
|
||||||
|
R.Add_Test (new String_to_Real_Test);
|
||||||
|
return R;
|
||||||
|
end Suite;
|
||||||
|
end Generic_String_to_Float_Test;
|
||||||
|
|
||||||
|
package String_to_Float_Test is new Generic_String_to_Float_Test (
|
||||||
|
Float, "Float", String_To_Float);
|
||||||
|
|
||||||
|
package String_to_Long_Float_Test is new Generic_String_to_Float_Test (
|
||||||
|
Long_Float, "Long_Float", String_To_Long_Float);
|
||||||
|
|
||||||
|
function Suite return Access_Test_Suite is
|
||||||
|
R : Access_Test_Suite := new Test_Suite;
|
||||||
|
begin
|
||||||
|
R.Add_Test (String_to_Float_Test.Suite);
|
||||||
|
R.Add_Test (String_to_Long_Float_Test.Suite);
|
||||||
|
return R;
|
||||||
|
end Suite;
|
||||||
|
|
||||||
|
end VSSL.Floating_Point.Conversion_Test;
|
8
source/test/vssl-floating_point-conversion_test.ads
Normal file
8
source/test/vssl-floating_point-conversion_test.ads
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
with AUnit.Test_Suites;
|
||||||
|
use AUnit.Test_Suites;
|
||||||
|
|
||||||
|
package VSSL.Floating_Point.Conversion_Test is
|
||||||
|
|
||||||
|
function Suite return Access_Test_Suite;
|
||||||
|
|
||||||
|
end VSSL.Floating_Point.Conversion_Test;
|
|
@ -1,5 +1,6 @@
|
||||||
with VSSL.Floating_Point.Approximate_Absolute_Test;
|
with VSSL.Floating_Point.Approximate_Absolute_Test;
|
||||||
with VSSL.Floating_Point.Approximate_Test;
|
with VSSL.Floating_Point.Approximate_Test;
|
||||||
|
with VSSL.Floating_Point.Conversion_Test;
|
||||||
with VSSL.Floating_Point.Quaternions;
|
with VSSL.Floating_Point.Quaternions;
|
||||||
with VSSL.Floating_Point.Generic_Quaternions.Test;
|
with VSSL.Floating_Point.Generic_Quaternions.Test;
|
||||||
|
|
||||||
|
@ -13,6 +14,7 @@ package body VSSL.Floating_Point.Test is
|
||||||
begin
|
begin
|
||||||
R.Add_Test (Approximate_Absolute_Test.Suite);
|
R.Add_Test (Approximate_Absolute_Test.Suite);
|
||||||
R.Add_Test (Approximate_Test.Suite);
|
R.Add_Test (Approximate_Test.Suite);
|
||||||
|
R.Add_Test (Conversion_Test.Suite);
|
||||||
R.Add_Test (Quaternions_Test.Suite);
|
R.Add_Test (Quaternions_Test.Suite);
|
||||||
return R;
|
return R;
|
||||||
end;
|
end;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
with VSSL.Champernowne_Constant.Test;
|
with VSSL.Champernowne_Constant.Test;
|
||||||
with VSSL.Combinatorial.Test;
|
with VSSL.Combinatorial.Test;
|
||||||
|
with VSSL.Conversions.Test;
|
||||||
with VSSL.Fixed_Point.Test;
|
with VSSL.Fixed_Point.Test;
|
||||||
with VSSL.Floating_Point.Test;
|
with VSSL.Floating_Point.Test;
|
||||||
with VSSL.Integers.Test;
|
with VSSL.Integers.Test;
|
||||||
|
@ -13,6 +14,7 @@ package body VSSL.Test is
|
||||||
R.Add_Test (VSSL.Extensible_Arithmetic.Test.Suite);
|
R.Add_Test (VSSL.Extensible_Arithmetic.Test.Suite);
|
||||||
R.Add_Test (VSSL.Champernowne_Constant.Test.Suite);
|
R.Add_Test (VSSL.Champernowne_Constant.Test.Suite);
|
||||||
R.Add_Test (VSSL.Combinatorial.Test.Suite);
|
R.Add_Test (VSSL.Combinatorial.Test.Suite);
|
||||||
|
R.Add_Test (VSSL.Conversions.Test.Suite);
|
||||||
R.Add_Test (VSSL.Fixed_Point.Test.Suite);
|
R.Add_Test (VSSL.Fixed_Point.Test.Suite);
|
||||||
R.Add_Test (VSSL.Floating_Point.Test.Suite);
|
R.Add_Test (VSSL.Floating_Point.Test.Suite);
|
||||||
R.Add_Test (VSSL.Integers.Test.Suite);
|
R.Add_Test (VSSL.Integers.Test.Suite);
|
||||||
|
|
|
@ -4,4 +4,8 @@ package VSSL.Test_Cases.Traits is
|
||||||
|
|
||||||
package Integer_Traits is new Type_Traits (Integer, "Integer", Integer'Image, "=");
|
package Integer_Traits is new Type_Traits (Integer, "Integer", Integer'Image, "=");
|
||||||
|
|
||||||
|
function String_Image (S : String) return String is ("""" & S & """");
|
||||||
|
|
||||||
|
package String_Traits is new Type_Traits (String, "String", String_Image, "=");
|
||||||
|
|
||||||
end VSSL.Test_Cases.Traits;
|
end VSSL.Test_Cases.Traits;
|
||||||
|
|
Loading…
Reference in a new issue