From: Shark8 <onewingedshark@gmail.com>
Subject: Re: Fixed vs float and precision and conversions
Date: Wed, 8 Jul 2020 09:16:37 -0700 (PDT) [thread overview]
Message-ID: <518ff68b-1017-4775-8248-c40048b4fe67o@googlegroups.com> (raw)
In-Reply-To: <re3vbb$kca$1@dont-email.me>
On Wednesday, July 8, 2020 at 2:15:43 AM UTC-6, björn lundin wrote:
> Den 2020-07-07 kl. 23:58, skrev Shark8:
> > On Tuesday, July 7, 2020 at 3:10:22 PM UTC-6, björn lundin wrote:
> >>
> >> I have a fixed type
> >> type Fixed_Type is delta 0.001 digits 18;
> >>
> >> but JSON does not support that. So I get floats instead.
> > This is a limitation of JSON, IIUC: all numeric are IEE754 floats -- see: https://www.json.org/json-en.html
>
> Yes.
>
> >
> > If you have access to both sides of the serialization, you could define an intermediate serialization say a string of "Fixed_Type#value#" where 'value' is the string-representation you need. -- You can extract the value by indexing on the '#' characters, extracting the portion in between, and feeding that via Fixed_Type'Value( EXTRACTED_SUBSTRING ), and produce it via "Fixed_Type#" & Fixed_Type'Image( fp_value ) & '#'.
>
> Interesting - but for another project.
> Here, I do not own the other side.
>
> Perhaps I should have stated that the other side is Betfair, and in this
> case I get odds of horse races via their API.
> The only valid odds are in a fixed set of numbers like
>
> they have small increments in the beginning, which increase as the odds
> go up
> like this partial array shows where
> type Tics_Type is new integer range 1 .. 350;
>
> Global_Odds_Table : array(Tics_Type'Range) of Fixed_Type := (
> 1.01, 1.02, 1.03, 1.04, 1.05,
> ...
> 2.00, 2.02, 2.04, 2.06, 2.08, 2.10,
> ...
> 3.00, 3.05, 3.10, 3.15, 3.20, 3.25,
> ...
> 4.00, 4.10, 4.20, 4.30, 4.40, 4.50,
> ...
> 5.00, 5.10, 5.20, 5.30, 5.40, 5.50,
> ...
> 10.00, 10.50, 11.00, 11.50, 12.00, 12.50,
> ...
> 20.00, 21.00, 22.00, 23.00, 24.00, 25.00,
> ...
> 50.00, 55.00, 60.00, 65.00, 70.00, 75.00,
> ...
> 100.00, 110.00, 120.00, 130.00, 140.00, 150.00,
> ...
> 960.00, 970.00, 980.00, 990.00,1000.00);
>
>
> so I get 5.1 from the JSON, which is occasionaly converted to 5.099,
> which I have trouble to find in the array above.
> I am now thinking of traversing it and make an absolute diff like
> abs(myval - arrayval) and pick the one with smallest diff.
>
> But my idea of using fixed was to escape the rounding errors.
> But hmm, here it is about feeding data _into_ the system, and here I'll
> get the error, while the rest will work nice.
>
> Hmm, I need to do some testing
>
> Thanks for the reply
>
>
> --
> Björn
Ok, so one thing to keep in mind here is that type-wise you're dealing not with two types, but *three* -- the type on the other side, the values in the Global_Odds_Table; the IEEE754 transport, via JSON serialization and deserialization; and the type on your side, Fixed_Type.
So then, the correct way to set up your end of things is to have a Fixed_Type which only has the values of Global_Odds_Table for your general-purpose/internal-usage, and have a conversion function for handling the IEEE754; here you are:
Lowest_Odds : Constant := 1.01;
Highest_Odds : Constant := 1_000.00;
type Odds_Base is delta 0.001 digits 18 range Lowest_Odds..Highest_Odds;
Subtype Odds is Odds_Base -- range Lowest_Odds..Hihgest_Odds
with Predicate_Failure => raise Constraint_Error with
Odds_Base'Image(Odds) & " is not a valid value.",
Static_Predicate => Odds in
-- Global_Odds_Table
1.01 | 1.02 | 1.03 | 1.04 | 1.05 |
2.00 | 2.02 | 2.04 | 2.06 | 2.08 | 2.10 |
3.00 | 3.05 | 3.10 | 3.15 | 3.20 | 3.25 |
4.00 | 4.10 | 4.20 | 4.30 | 4.40 | 4.50 |
5.00 | 5.10 | 5.20 | 5.30 | 5.40 | 5.50 |
10.00 | 10.50 | 11.00 | 11.50 | 12.00 | 12.50 |
20.00 | 21.00 | 22.00 | 23.00 | 24.00 | 25.00 |
50.00 | 55.00 | 60.00 | 65.00 | 70.00 | 75.00 |
100.00 | 110.00 | 120.00 | 130.00 | 140.00 | 150.00 |
960.00 | 970.00 | 980.00 | 990.00 |1000.00 ;
Function Convert( Input : Interfaces.IEEE_Float_32 ) return Odds is
use Interfaces;
Begin
Ada.Text_IO.Put_Line( "Input:" & Input'Image );
Ada.Text_IO.Put_Line( "OB:" & Odds_Base'Round(Input)'Image );
Return Odds'Round( Input );
Exception
When Constraint_Error =>
-- Handle out-of-range errors.
if Input < Lowest_Odds then
return Lowest_Odds;
elsif Input > Highest_Odds then
return Highest_Odds;
else
declare
-- Global_Odds_Table
Table : Constant Array (Positive range <>) of IEEE_Float_32 :=
( 1.01, 1.02, 1.03, 1.04, 1.05,
2.00, 2.02, 2.04, 2.06, 2.08, 2.10,
3.00, 3.05, 3.10, 3.15, 3.20, 3.25,
4.00, 4.10, 4.20, 4.30, 4.40, 4.50,
5.00, 5.10, 5.20, 5.30, 5.40, 5.50,
10.00, 10.50, 11.00, 11.50, 12.00, 12.50,
20.00, 21.00, 22.00, 23.00, 24.00, 25.00,
50.00, 55.00, 60.00, 65.00, 70.00, 75.00,
100.00, 110.00, 120.00, 130.00, 140.00, 150.00,
960.00, 970.00, 980.00, 990.00,1000.00 );
Closest_Index : Positive := 1;
Closest_Value : IEEE_Float_32 := IEEE_Float_32'Last;
begin
For X in Table'Range loop
if abs (Input - Table(X)) < Closest_Value then
Closest_Value:= abs (Input - Table(X));
Closest_Index:= X;
end if;
end loop;
Return Odds'Round( Table(Closest_Index) );
end;
end if;
End Convert;
The bad thing here is that you have to repeat Global_Odds_Table, though this isn't so bad as the second is fully contained within the exception-handler; further, searching the table is done only when 'Round cannot be used directly. Also, this version does catch out of bounds errors and coerce them to the nearest bound. -- You might want to write a one-off program to generate the Predicate-form and array-value form of Global_Odds_Table, since there's 350 values.
next prev parent reply other threads:[~2020-07-08 16:16 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-07-07 21:10 Fixed vs float and precision and conversions Björn Lundin
2020-07-07 21:30 ` Niklas Holsti
2020-07-08 8:17 ` Björn Lundin
2020-07-07 21:58 ` Shark8
2020-07-08 8:15 ` Björn Lundin
2020-07-08 16:16 ` Shark8 [this message]
2020-07-08 18:08 ` Björn Lundin
2020-07-08 18:10 ` Björn Lundin
2020-07-08 18:21 ` Niklas Holsti
2020-07-08 19:39 ` Björn Lundin
2020-07-08 20:34 ` Niklas Holsti
2020-07-08 21:24 ` Björn Lundin
2020-07-09 7:11 ` Niklas Holsti
2020-07-08 18:36 ` Dmitry A. Kazakov
2020-07-08 19:41 ` Björn Lundin
2020-07-09 6:20 ` Dmitry A. Kazakov
2020-07-09 7:23 ` Björn Lundin
2020-07-09 7:49 ` Dmitry A. Kazakov
2020-07-08 21:16 ` Shark8
2020-07-08 21:47 ` Björn Lundin
replies disabled
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox