From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on ip-172-31-74-118.ec2.internal X-Spam-Level: X-Spam-Status: No, score=0.5 required=3.0 tests=BAYES_05,FORGED_GMAIL_RCVD, FREEMAIL_FROM autolearn=no autolearn_force=no version=3.4.4 Path: eternal-september.org!reader01.eternal-september.org!.POSTED!not-for-mail From: =?UTF-8?Q?Bj=c3=b6rn_Lundin?= Newsgroups: comp.lang.ada Subject: Re: Fixed vs float and precision and conversions Date: Wed, 8 Jul 2020 20:08:13 +0200 Organization: A noiseless patient Spider Message-ID: References: <756885db-118a-4d76-b90d-e547a3cabf28o@googlegroups.com> <518ff68b-1017-4775-8248-c40048b4fe67o@googlegroups.com> Mime-Version: 1.0 Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: 8bit Injection-Date: Wed, 8 Jul 2020 18:08:14 -0000 (UTC) Injection-Info: reader02.eternal-september.org; posting-host="bbc4443e166da1163e3df9d7300a854c"; logging-data="22877"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1+k61bt++rHf9a/C3qnWlVG" User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:68.0) Gecko/20100101 Thunderbird/68.9.0 Cancel-Lock: sha1:A41SeaJeO6gm/mvk81zBM61XqeA= In-Reply-To: <518ff68b-1017-4775-8248-c40048b4fe67o@googlegroups.com> Content-Language: sv Xref: reader01.eternal-september.org comp.lang.ada:59398 List-Id: Den 2020-07-08 kl. 18:16, skrev Shark8: > 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: >>>> > 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. hmm no. valuies in global_odds_table are fixed_type Global_Odds_Table : array(Tics_Type'Range) of Fixed_Type := ( The type on the other side arrive in JSON as float. In deserialisation I convert to Fixed_Type. I don't quite follow you > > 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. > hmm, nice. I'll implement this if not the thing I implemented and deployed *10* minutes ago works. it is based on the fact that I have a float-to-fixed_type converted price in a fixed_type variable. It -as it turns out - can be * too low for a specific value (as 5.099 vs 5.10) * correct * too high for a specific value So I call below function with the converted value, and then I look up returned index in the table/array It also only goes to fix things only if incorrect/illegal value --------- function Get_Tic_Index(Price : Fixed_Type) return Tics_Type is begin --optimistic approch - we have the coorect conversion for I in Global_Odds_Table'Range loop if Global_Odds_Table(I) = Price then return I; end if; end loop; -- ok - did not find any -> bad float then -- it has to be a valid value within min an max declare P : Fixed_Type; D : Fixed_Type := 0.001 ; Min : Fixed_Type; Max : Fixed_Type; begin -- Find Index in odds table which is just below given odds for I in Global_Odds_Table'Range loop if Global_Odds_Table(I) < Price then Min := Global_Odds_Table(I); else exit; -- must have found it end if; end loop; -- Find Index in odds table which is just above given odds for I in Global_Odds_Table'Range loop if Global_Odds_Table(I) > Price then Max := Global_Odds_Table(I); exit; end if; end loop; -- now step carefully util we get a hit or we have to give up Log("Get_Tic_Index", "try fixing bad float price " & Price'Img); P := Min + D; loop for I in Global_Odds_Table'Range loop if Global_Odds_Table(I) = P then Log("Get_Tic_Index", "fixed bad float - min/max " & Min'Img & " / " & Max'Img); return I; end if; end loop; exit when P > Max; --give up, and propagate exception Log("Get_Tic_Index", "fixing bad float p/min/max " & P'Img & Min'Img & " / " & Max'Img); P := P + D; end loop; Log("Get_Tic_Index", "did not fix bad float min/max " & Min'Img & " / " & Max'Img); end; raise Bad_Odds with Price'Img; end Get_Tic_Index; --------- Thanks for the time and effort -- Björn