comp.lang.ada
 help / color / mirror / Atom feed
* Fixed vs float and precision and conversions
@ 2020-07-07 21:10 Björn Lundin
  2020-07-07 21:30 ` Niklas Holsti
  2020-07-07 21:58 ` Shark8
  0 siblings, 2 replies; 20+ messages in thread
From: Björn Lundin @ 2020-07-07 21:10 UTC (permalink / raw)



Hi !

I've for years run an interface towards extenal part on a raspberry pi
that communicates with JSON over http (JSONRPC2)

the versions are

bnl@pibetbot:~ $ gnatls -v

GNATLS 6.3.0
Copyright (C) 1997-2016, Free Software Foundation, Inc.
...

bnl@pibetbot:~ $ uname -a
Linux pibetbot 4.14.79-v7+ #1159 SMP Sun Nov 4 17:50:20 GMT 2018 armv7l 
GNU/Linux
bnl@pibetbot:~ $ cat /etc/deb
debconf.conf    debian_version
bnl@pibetbot:~ $ cat /etc/deb
debconf.conf    debian_version
bnl@pibetbot:~ $ cat /etc/debian_version
9.4


I have found this reliable but suddenly I have got some rounding 
troubles. Or I perhaps just discovered it now.


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.


I use gnatcoll.json as parser by the way


   procedure Get_Value(Container: in    Json_Value;
                       Field    : in     String;
                       Target   : in out Fixed_Type;
                       Found    :    out Boolean ) is
     Tmp : Float := 0.0;
   begin
     if Container.Has_Field(Field) then
       Tmp := Container.Get(Field);
       Found := True;
       Target := Fixed_Type(Tmp);
     else
       Found := False;
     end if;
   end Get_Value;


The message (JSON) contains a value 5.10 (in a float), but that is 
converted (sometimes I think) to the fixed_type variable with value 
5.099. This gets me into trouble further down in the code.

So - What should I do instead?

should I express my Fixed_Type in another way?

I need to be able to express 6.5 % (0.065) which I could not with
type Fixed_Type is delta 0.01 digits 18;




-- 
Björn

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: Fixed vs float and precision and conversions
  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
  1 sibling, 1 reply; 20+ messages in thread
From: Niklas Holsti @ 2020-07-07 21:30 UTC (permalink / raw)


On 2020-07-08 0:10, Björn Lundin wrote:
> 
> Hi !
> 
> I've for years run an interface towards extenal part on a raspberry pi
> that communicates with JSON over http (JSONRPC2)
> 
> the versions are
> 
> bnl@pibetbot:~ $ gnatls -v
> 
> GNATLS 6.3.0
> Copyright (C) 1997-2016, Free Software Foundation, Inc.
> ...
> 
> bnl@pibetbot:~ $ uname -a
> Linux pibetbot 4.14.79-v7+ #1159 SMP Sun Nov 4 17:50:20 GMT 2018 armv7l 
> GNU/Linux
> bnl@pibetbot:~ $ cat /etc/deb
> debconf.conf    debian_version
> bnl@pibetbot:~ $ cat /etc/deb
> debconf.conf    debian_version
> bnl@pibetbot:~ $ cat /etc/debian_version
> 9.4
> 
> 
> I have found this reliable but suddenly I have got some rounding 
> troubles. Or I perhaps just discovered it now.
> 
> 
> 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.
> 
> 
> I use gnatcoll.json as parser by the way
> 
> 
>    procedure Get_Value(Container: in    Json_Value;
>                        Field    : in     String;
>                        Target   : in out Fixed_Type;
>                        Found    :    out Boolean ) is
>      Tmp : Float := 0.0;
>    begin
>      if Container.Has_Field(Field) then
>        Tmp := Container.Get(Field);
>        Found := True;
>        Target := Fixed_Type(Tmp);
>      else
>        Found := False;
>      end if;
>    end Get_Value;
> 
> 
> The message (JSON) contains a value 5.10 (in a float), but that is 
> converted (sometimes I think) to the fixed_type variable with value 
> 5.099. This gets me into trouble further down in the code.
> 
> So - What should I do instead?

According to RM 4.6(31), conversion to a decimal fixed-point type does 
not round, but truncates toward zero if the operand is not a multiple of 
the "small" of the target type, which is usually the case here if Floats 
are base-two.

You should perhaps change the conversion (Target := Fixed_Type(Tmp)) to 
round, by doing Target := Fixed_Point'Round (Tmp).

Note, I haven't tried it.

-- 
Niklas Holsti
niklas holsti tidorum fi
       .      @       .

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: Fixed vs float and precision and conversions
  2020-07-07 21:10 Fixed vs float and precision and conversions Björn Lundin
  2020-07-07 21:30 ` Niklas Holsti
@ 2020-07-07 21:58 ` Shark8
  2020-07-08  8:15   ` Björn Lundin
  1 sibling, 1 reply; 20+ messages in thread
From: Shark8 @ 2020-07-07 21:58 UTC (permalink / raw)


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

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 ) & '#'.

> 
> 
> I use gnatcoll.json as parser by the way
> 
> 
>    procedure Get_Value(Container: in    Json_Value;
>                        Field    : in     String;
>                        Target   : in out Fixed_Type;
>                        Found    :    out Boolean ) is
>      Tmp : Float := 0.0;
>    begin
>      if Container.Has_Field(Field) then
>        Tmp := Container.Get(Field);
>        Found := True;
>        Target := Fixed_Type(Tmp);
>      else
>        Found := False;
>      end if;
>    end Get_Value;
> 
> 
> The message (JSON) contains a value 5.10 (in a float), but that is 
> converted (sometimes I think) to the fixed_type variable with value 
> 5.099. This gets me into trouble further down in the code.
> 
> So - What should I do instead?
> 
> should I express my Fixed_Type in another way?
> 
> I need to be able to express 6.5 % (0.065) which I could not with
> type Fixed_Type is delta 0.01 digits 18;
> 
> 
> 
> 
> -- 
> Björn

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: Fixed vs float and precision and conversions
  2020-07-07 21:58 ` Shark8
@ 2020-07-08  8:15   ` Björn Lundin
  2020-07-08 16:16     ` Shark8
  0 siblings, 1 reply; 20+ messages in thread
From: Björn Lundin @ 2020-07-08  8:15 UTC (permalink / raw)


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

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: Fixed vs float and precision and conversions
  2020-07-07 21:30 ` Niklas Holsti
@ 2020-07-08  8:17   ` Björn Lundin
  0 siblings, 0 replies; 20+ messages in thread
From: Björn Lundin @ 2020-07-08  8:17 UTC (permalink / raw)


Den 2020-07-07 kl. 23:30, skrev Niklas Holsti:

> 
> According to RM 4.6(31), conversion to a decimal fixed-point type does 
> not round, but truncates toward zero if the operand is not a multiple of 
> the "small" of the target type, which is usually the case here if Floats 
> are base-two.
> 
> You should perhaps change the conversion (Target := Fixed_Type(Tmp)) to 
> round, by doing Target := Fixed_Point'Round (Tmp).
> 
> Note, I haven't tried it.

Ok - nice idea. I'll try it, thanks.



-- 
Björn

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: Fixed vs float and precision and conversions
  2020-07-08  8:15   ` Björn Lundin
@ 2020-07-08 16:16     ` Shark8
  2020-07-08 18:08       ` Björn Lundin
  0 siblings, 1 reply; 20+ messages in thread
From: Shark8 @ 2020-07-08 16:16 UTC (permalink / raw)


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.

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: Fixed vs float and precision and conversions
  2020-07-08 16:16     ` Shark8
@ 2020-07-08 18:08       ` Björn Lundin
  2020-07-08 18:10         ` Björn Lundin
  2020-07-08 21:16         ` Shark8
  0 siblings, 2 replies; 20+ messages in thread
From: Björn Lundin @ 2020-07-08 18:08 UTC (permalink / raw)


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

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: Fixed vs float and precision and conversions
  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 18:36           ` Dmitry A. Kazakov
  2020-07-08 21:16         ` Shark8
  1 sibling, 2 replies; 20+ messages in thread
From: Björn Lundin @ 2020-07-08 18:10 UTC (permalink / raw)


Den 2020-07-08 kl. 20:08, skrev Björn Lundin:

The main reason for asking was to see if I got the whole concept
of fixed types wrong or not.
I did expect
'You should do this or that one-liner' as Niklas proposed.
I did not get that to work though


-- 
Björn

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: Fixed vs float and precision and conversions
  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 18:36           ` Dmitry A. Kazakov
  1 sibling, 1 reply; 20+ messages in thread
From: Niklas Holsti @ 2020-07-08 18:21 UTC (permalink / raw)


On 2020-07-08 21:10, Björn Lundin wrote:
> Den 2020-07-08 kl. 20:08, skrev Björn Lundin:
> 
> The main reason for asking was to see if I got the whole concept
> of fixed types wrong or not.
> I did expect
> 'You should do this or that one-liner' as Niklas proposed.
> I did not get that to work though

Oh. What happened when you tried? How did it fail?

-- 
Niklas Holsti
niklas holsti tidorum fi
       .      @       .

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: Fixed vs float and precision and conversions
  2020-07-08 18:10         ` Björn Lundin
  2020-07-08 18:21           ` Niklas Holsti
@ 2020-07-08 18:36           ` Dmitry A. Kazakov
  2020-07-08 19:41             ` Björn Lundin
  1 sibling, 1 reply; 20+ messages in thread
From: Dmitry A. Kazakov @ 2020-07-08 18:36 UTC (permalink / raw)


On 08/07/2020 20:10, Björn Lundin wrote:
> Den 2020-07-08 kl. 20:08, skrev Björn Lundin:
> 
> The main reason for asking was to see if I got the whole concept
> of fixed types wrong or not.

Fixed-point is conceptually a scaled integer. You should deal with it 
accordingly. [It could be a bit surprising in Ada where conversion to 
integer rounds. In most languages conversion to integer truncates]

> I did expect
> 'You should do this or that one-liner' as Niklas proposed.
> I did not get that to work though

What do you mean it does not work? Of course T'Round works for 
fixed-point types. Simplifying it for positive numbers only T'Round is 
roughly same as:

    T (X + T'Small / 2.0)

As a side note. Consider the problem of splitting an interval into 
same-width subintervals. If each subinterval is denoted by its center, 
you have a problem with the margins of the whole interval as they do not 
denote any center. Furthermore if zero is included that again poses a 
question whether it should be in a center of a subinterval (which is 
then both negative and positive!) or at the margin of two subintervals 
(and thus not represented as a center!). It is a difficult problem which 
does not have universal or even intuitive solution. Thus do not expect 
one-liners.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: Fixed vs float and precision and conversions
  2020-07-08 18:21           ` Niklas Holsti
@ 2020-07-08 19:39             ` Björn Lundin
  2020-07-08 20:34               ` Niklas Holsti
  0 siblings, 1 reply; 20+ messages in thread
From: Björn Lundin @ 2020-07-08 19:39 UTC (permalink / raw)


Den 2020-07-08 kl. 20:21, skrev Niklas Holsti:
> On 2020-07-08 21:10, Björn Lundin wrote:
>> Den 2020-07-08 kl. 20:08, skrev Björn Lundin:
>>
>> The main reason for asking was to see if I got the whole concept
>> of fixed types wrong or not.
>> I did expect
>> 'You should do this or that one-liner' as Niklas proposed.
>> I did not get that to work though
> 
> Oh. What happened when you tried? How did it fail?
> 

I did a test routine like below,
but realized that Float(5.10) - which was converted to Fixed_Type(5.099)
is a valid fixed_type of course.

so
       Fix1 := Fixed_Type(Flt);
or
       Fix2 := Fixed_Type'Round(Flt);

does not really matter, since both may return 5.099
when given 5.10

It is at least not certain that the number expressed in fixed_type is 
one of them in the array below.
And that is my real problem - I think.


   ------------------------------
   type Fixed_Type is delta 0.001 digits 18;
   Bad_odds : exception;
   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,   1.06,   1.07,   1.08,   1.09,
     1.10,   1.11,   1.12,   1.13,   1.14,
     1.15,   1.16,   1.17,   1.18,   1.19,
     1.20,   1.21,   1.22,   1.23,   1.24,
     1.25,   1.26,   1.27,   1.28,   1.29,
     1.30,   1.31,   1.32,   1.33,   1.34,
     1.35,   1.36,   1.37,   1.38,   1.39,
     1.40,   1.41,   1.42,   1.43,   1.44,
     1.45,   1.46,   1.47,   1.48,   1.49,
     1.50,   1.51,   1.52,   1.53,   1.54,
     1.55,   1.56,   1.57,   1.58,   1.59,
     1.60,   1.61,   1.62,   1.63,   1.64,
     1.65,   1.66,   1.67,   1.68,   1.69,
     1.70,   1.71,   1.72,   1.73,   1.74,
     1.75,   1.76,   1.77,   1.78,   1.79,
     1.80,   1.81,   1.82,   1.83,   1.84,
     1.85,   1.86,   1.87,   1.88,   1.89,
     1.90,   1.91,   1.92,   1.93,   1.94,
     1.95,   1.96,   1.97,   1.98,   1.99,
     2.00,   2.02,   2.04,   2.06,   2.08,
     2.10,   2.12,   2.14,   2.16,   2.18,
     2.20,   2.22,   2.24,   2.26,   2.28,
     2.30,   2.32,   2.34,   2.36,   2.38,
     2.40,   2.42,   2.44,   2.46,   2.48,
     2.50,   2.52,   2.54,   2.56,   2.58,
     2.60,   2.62,   2.64,   2.66,   2.68,
     2.70,   2.72,   2.74,   2.76,   2.78,
     2.80,   2.82,   2.84,   2.86,   2.88,
     2.90,   2.92,   2.94,   2.96,   2.98,
     3.00,   3.05,   3.10,   3.15,   3.20,
     3.25,   3.30,   3.35,   3.40,   3.45,
     3.50,   3.55,   3.60,   3.65,   3.70,
     3.75,   3.80,   3.85,   3.90,   3.95,
     4.00,   4.10,   4.20,   4.30,   4.40,
     4.50,   4.60,   4.70,   4.80,   4.90,
     5.00,   5.10,   5.20,   5.30,   5.40,
     5.50,   5.60,   5.70,   5.80,   5.90,
     6.00,   6.20,   6.40,   6.60,   6.80,
     7.00,   7.20,   7.40,   7.60,   7.80,
     8.00,   8.20,   8.40,   8.60,   8.80,
     9.00,   9.20,   9.40,   9.60,   9.80,
    10.00,  10.50,  11.00,  11.50,  12.00,
    12.50,  13.00,  13.50,  14.00,  14.50,
    15.00,  15.50,  16.00,  16.50,  17.00,
    17.50,  18.00,  18.50,  19.00,  19.50,
    20.00,  21.00,  22.00,  23.00,  24.00,
    25.00,  26.00,  27.00,  28.00,  29.00,
    30.00,  32.00,  34.00,  36.00,  38.00,
    40.00,  42.00,  44.00,  46.00,  48.00,
    50.00,  55.00,  60.00,  65.00,  70.00,
    75.00,  80.00,  85.00,  90.00,  95.00,
  100.00, 110.00, 120.00, 130.00, 140.00,
  150.00, 160.00, 170.00, 180.00, 190.00,
  200.00, 210.00, 220.00, 230.00, 240.00,
  250.00, 260.00, 270.00, 280.00, 290.00,
  300.00, 310.00, 320.00, 330.00, 340.00,
  350.00, 360.00, 370.00, 380.00, 390.00,
  400.00, 410.00, 420.00, 430.00, 440.00,
  450.00, 460.00, 470.00, 480.00, 490.00,
  500.00, 510.00, 520.00, 530.00, 540.00,
  550.00, 560.00, 570.00, 580.00, 590.00,
  600.00, 610.00, 620.00, 630.00, 640.00,
  650.00, 660.00, 670.00, 680.00, 690.00,
  700.00, 710.00, 720.00, 730.00, 740.00,
  750.00, 760.00, 770.00, 780.00, 790.00,
  800.00, 810.00, 820.00, 830.00, 840.00,
  850.00, 860.00, 870.00, 880.00, 890.00,
  900.00, 910.00, 920.00, 930.00, 940.00,
  950.00, 960.00, 970.00, 980.00, 990.00,
  1000.00);



  function Get_Tic_Index(Price : Fixed_Type) return Tics_Type is
   begin
     for I in Global_Odds_Table'Range loop
       if Global_Odds_Table(I) = Price then
         return I;
       end if;
     end loop;
     raise Bad_Odds with Price'Img;
   end Get_Tic_Index;


  procedure Test_Float_To_Fix_Conversion is
     Flt : Float := 1.0;
     Fix1 : Fixed_Type := 0.0;
     Fix2 : Fixed_Type := 0.0;
     Tc1 : Tics_Type:= Tics_Type'First;
     Tc2 : Tics_Type:= Tics_Type'First;
   begin
     loop
       Flt := Flt + 0.001;

       Fix1 := Fixed_Type(Flt);
       Fix2 := Fixed_Type'Round(Flt);

       begin
         Tc1 := Get_Tic_Index(Fix1);
         Log("Test_Float_To_Fix_Conversion", "1 " &  Fix1'Img &  " -> " 
& Tc1'Img);
       exception
         when Bad_Odds =>
           Log("Test_Float_To_Fix_Conversion", "Bad odds 1 " & Fix1'Img);
       end;

       begin
         Tc2 := Get_Tic_Index(Fix2);
         Log("Test_Float_To_Fix_Conversion", "2 " &  Fix2'Img & " -> " & 
Tc2'Img);
       exception
         when Bad_Odds =>
           Log("Test_Float_To_Fix_Conversion", "Bad odds 2 " & Fix2'Img);
       end;
       exit when Flt > 1000.0;
     end loop;

   end Test_Float_To_Fix_Conversion;
   ------------------------------------------

-- 
Björn

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: Fixed vs float and precision and conversions
  2020-07-08 18:36           ` Dmitry A. Kazakov
@ 2020-07-08 19:41             ` Björn Lundin
  2020-07-09  6:20               ` Dmitry A. Kazakov
  0 siblings, 1 reply; 20+ messages in thread
From: Björn Lundin @ 2020-07-08 19:41 UTC (permalink / raw)


Den 2020-07-08 kl. 20:36, skrev Dmitry A. Kazakov:
> On 08/07/2020 20:10, Björn Lundin wrote:
>> Den 2020-07-08 kl. 20:08, skrev Björn Lundin:
>>
>> The main reason for asking was to see if I got the whole concept
>> of fixed types wrong or not.
> 
> Fixed-point is conceptually a scaled integer. You should deal with it 
> accordingly. [It could be a bit surprising in Ada where conversion to 
> integer rounds. In most languages conversion to integer truncates]
> 
>> I did expect
>> 'You should do this or that one-liner' as Niklas proposed.
>> I did not get that to work though
> 
> What do you mean it does not work? Of course T'Round works for 
> fixed-point types. 

Yes, of course *that* works. But unfortuantly, it does not solve my problem.

As I replied to Niklas:
It is at least not certain that the number expressed in fixed_type is 
one of them in the array below.
And that is my real problem - I think.


-- 
Björn

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: Fixed vs float and precision and conversions
  2020-07-08 19:39             ` Björn Lundin
@ 2020-07-08 20:34               ` Niklas Holsti
  2020-07-08 21:24                 ` Björn Lundin
  0 siblings, 1 reply; 20+ messages in thread
From: Niklas Holsti @ 2020-07-08 20:34 UTC (permalink / raw)


On 2020-07-08 22:39, Björn Lundin wrote:
> Den 2020-07-08 kl. 20:21, skrev Niklas Holsti:
>> On 2020-07-08 21:10, Björn Lundin wrote:
>>> Den 2020-07-08 kl. 20:08, skrev Björn Lundin:
>>>
>>> The main reason for asking was to see if I got the whole concept
>>> of fixed types wrong or not.
>>> I did expect
>>> 'You should do this or that one-liner' as Niklas proposed.
>>> I did not get that to work though
>>
>> Oh. What happened when you tried? How did it fail?
>>
> 
> I did a test routine like below,
> but realized that Float(5.10) - which was converted to Fixed_Type(5.099)
> is a valid fixed_type of course.


No, see below. You are confusing decimal (base-10) reals with binary 
(base-2) floats.


> so
>        Fix1 := Fixed_Type(Flt);
> or
>        Fix2 := Fixed_Type'Round(Flt);
> 
> does not really matter, since both may return 5.099
> when given 5.10


Wrong. The point is that Float'(5.10) is not exactly 5.10, because 
base-2 floats cannot represent decimal fractions exactly. Since the 
result, as you showed in your first post, of converting (with 
truncation) Float'(5.10) to Fixed_Type is 5.099, the actual (binary) 
value of Float'(5.10) is a little less than 5.10, so the truncation 
gives 5.099 instead of 5.100.

But Fixed_Type'Round (Float'(5.10)) will always give 5.100.


> It is at least not certain that the number expressed in fixed_type is 
> one of them in the array below.
> And that is my real problem - I think.


That is certainly true -- if you don't know anything about the Float 
number, then you won't know much about the result of Fixed_Type'Round on 
that Float number. If you want to be sure that the result is one of the 
numbers in your table, you have to check.


>    ------------------------------
>    type Fixed_Type is delta 0.001 digits 18;
>    Bad_odds : exception;
>    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,   1.06,   1.07,   1.08,   1.09,


    [snip]


>   950.00, 960.00, 970.00, 980.00, 990.00,
>   1000.00);


If your Float numbers are as high as that (1000), you are approaching 
the limit of Float precision (about 7 decimal digits) compared to the 
delta of 0.001 for the Fixed_Type. That is, the Float representation of 
a Fixed_Type value close to 1000.0 might just be off by more than 
0.0005, in which case Fixed_Type'Round would give the corresponding (but 
wrong) value.

However, I tried Fixed_Type'Round on Float values of 999.998, 999.999, 
1000.001 and 1000.002, and got the corresponding Fixed_Type values, so 
it may be ok.

But the values in the Global_Odds table are all given with two decimals, 
not three, so why not define Fixed_Type with delta 0.01, which avoids 
this possible Float precision problem, as well as being more apt?

-- 
Niklas Holsti
niklas holsti tidorum fi
       .      @       .

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: Fixed vs float and precision and conversions
  2020-07-08 18:08       ` Björn Lundin
  2020-07-08 18:10         ` Björn Lundin
@ 2020-07-08 21:16         ` Shark8
  2020-07-08 21:47           ` Björn Lundin
  1 sibling, 1 reply; 20+ messages in thread
From: Shark8 @ 2020-07-08 21:16 UTC (permalink / raw)


On Wednesday, July 8, 2020 at 12:08:16 PM UTC-6, björn lundin wrote:
> 
> hmm no. valuies in global_odds_table are fixed_type
>    Global_Odds_Table : array(Tics_Type'Range) of Fixed_Type := (

Except you don't *have*, in the things you are getting [from JSON], fixed-point.
You are getting IEEE-float, as a consequence of JSON's definition.
In order to find the proper values for a non-'Round-able you have to compare Floatingpoints to the acceptable-values in the table: for simplicity this means using the table-values as floats. [Conceptually they are universal-numbers.]

By putting the global-table in the convert function, as an array of floats, I got rid of the need for Tics_Type, as well as simplifying the translation (if-needed).

Take a look at the conversion function you provided, and the one I provided; there are two big differences: mine will return a valid Odds value, and that value will be that value from the table which is the closest value to the input-float.

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: Fixed vs float and precision and conversions
  2020-07-08 20:34               ` Niklas Holsti
@ 2020-07-08 21:24                 ` Björn Lundin
  2020-07-09  7:11                   ` Niklas Holsti
  0 siblings, 1 reply; 20+ messages in thread
From: Björn Lundin @ 2020-07-08 21:24 UTC (permalink / raw)


Den 2020-07-08 kl. 22:34, skrev Niklas Holsti:

> 
> No, see below. You are confusing decimal (base-10) reals with binary 
> (base-2) floats.

Yes.

>> It is at least not certain that the number expressed in fixed_type is 
>> one of them in the array below.
>> And that is my real problem - I think.
> 
> 
> That is certainly true -- if you don't know anything about the Float 
> number, then you won't know much about the result of Fixed_Type'Round on 
> that Float number. If you want to be sure that the result is one of the 
> numbers in your table, you have to check.
> 

yes - I realize that


> 
> But the values in the Global_Odds table are all given with two decimals, 
> not three, so why not define Fixed_Type with delta 0.01, which avoids 
> this possible Float precision problem, as well as being more apt?

Because I wanted to express 6.5% -> 0.065 in fixed_type as well.
I think I mentioned that in a post.

Fixed_type is used generally here (in this system) instead of float, not 
only for that array.

This may have been a bad design choise though.

-- 
Björn

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: Fixed vs float and precision and conversions
  2020-07-08 21:16         ` Shark8
@ 2020-07-08 21:47           ` Björn Lundin
  0 siblings, 0 replies; 20+ messages in thread
From: Björn Lundin @ 2020-07-08 21:47 UTC (permalink / raw)


Den 2020-07-08 kl. 23:16, skrev Shark8:
> On Wednesday, July 8, 2020 at 12:08:16 PM UTC-6, björn lundin wrote:
>>
>> hmm no. valuies in global_odds_table are fixed_type
>>     Global_Odds_Table : array(Tics_Type'Range) of Fixed_Type := (
> 
> Except you don't *have*, in the things you are getting [from JSON], fixed-point.
> You are getting IEEE-float, as a consequence of JSON's definition.
> In order to find the proper values for a non-'Round-able you have to compare Floatingpoints to the acceptable-values in the table: for simplicity this means using the table-values as floats. [Conceptually they are universal-numbers.]
> 


hmm, it is difficult to condense a case to a simple case that 
demostrates the problem - and then does not over-simplify it, compared 
to showing lots of things that removes clarity - but then seems to be 
needed anyway.


> By putting the global-table in the convert function, as an array of floats, I got rid of the need for Tics_Type, as well as simplifying the translation (if-needed).

Yes, but Tics_Type is needed anyway.
Say I want to green up (put my self were I win no matter outcome of event))

I say runner 1 wins @ 1.85 and risk €10
then later - when runner 1 seems to be winning, odds have dropped to 
1.25 i say runner 1 does NOT win @1.25 risk €16

if it wins I get €10 *(1.85 -1.0) = €8.5
I also loose the lay-bet = - €16 *(1.25 -1.0) = -€4.0
total win = €8.5 - €4.0 = €4.5

if it looses
I get the €16
and loose the €10 => €16 -€10 = €6

Sometimes you want to calculate how much to risk the second bet
and using the array is nice then.
Sometimes I can say I want to greenup on a delta-tics = 20
That makes calculations easy

> 
> Take a look at the conversion function you provided, and the one I provided; there are two big differences: mine will return a valid Odds value, and that value will be that value from the table which is the closest value to the input-float.


yes but if the odds are outside 1.01 -1000.0 I'd like to throw an exception.
You may be right that your function gets the closer value.
I will re-examine.

Thanks again


-- 
Björn

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: Fixed vs float and precision and conversions
  2020-07-08 19:41             ` Björn Lundin
@ 2020-07-09  6:20               ` Dmitry A. Kazakov
  2020-07-09  7:23                 ` Björn Lundin
  0 siblings, 1 reply; 20+ messages in thread
From: Dmitry A. Kazakov @ 2020-07-09  6:20 UTC (permalink / raw)


On 08/07/2020 21:41, Björn Lundin wrote:

> As I replied to Niklas:
> It is at least not certain that the number expressed in fixed_type is 
> one of them in the array below.

The array has varying step 0.01 to 10.0, your test has step 0.001. What 
do you expect? Of course it must fail at a very high rate from 9/1 to 
999/1, practically always.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: Fixed vs float and precision and conversions
  2020-07-08 21:24                 ` Björn Lundin
@ 2020-07-09  7:11                   ` Niklas Holsti
  0 siblings, 0 replies; 20+ messages in thread
From: Niklas Holsti @ 2020-07-09  7:11 UTC (permalink / raw)


On 2020-07-09 0:24, Björn Lundin wrote:
> Den 2020-07-08 kl. 22:34, skrev Niklas Holsti:

>> But the values in the Global_Odds table are all given with two 
>> decimals, not three, so why not define Fixed_Type with delta 0.01, 
>> which avoids this possible Float precision problem, as well as being 
>> more apt?
> 
> Because I wanted to express 6.5% -> 0.065 in fixed_type as well.
> I think I mentioned that in a post.

Oh yes, I didn't remember that. Sorry.

-- 
Niklas Holsti
niklas holsti tidorum fi
       .      @       .

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: Fixed vs float and precision and conversions
  2020-07-09  6:20               ` Dmitry A. Kazakov
@ 2020-07-09  7:23                 ` Björn Lundin
  2020-07-09  7:49                   ` Dmitry A. Kazakov
  0 siblings, 1 reply; 20+ messages in thread
From: Björn Lundin @ 2020-07-09  7:23 UTC (permalink / raw)


Den 2020-07-09 kl. 08:20, skrev Dmitry A. Kazakov:
> On 08/07/2020 21:41, Björn Lundin wrote:
> 
>> As I replied to Niklas:
>> It is at least not certain that the number expressed in fixed_type is 
>> one of them in the array below.
> 
> The array has varying step 0.01 to 10.0, your test has step 0.001. What 
> do you expect? Of course it must fail at a very high rate from 9/1 to 
> 999/1, practically always.
> 

welll, in practice not always.
It only fails when - like my example -

Fixed_Type(float(5.10)) becomes 5.099

and its been running with that construct since 2014,
and I only noticed now. So - not always, actually very seldom.

I did expect floating comparison error to go away using fixed type,
but I forgot about 'garbage in -> garbage out'

I don't have that kind of rounding errors once the values are converted 
to fixed_type but I did not realize that I had them in the conversion.

-- 
Björn

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: Fixed vs float and precision and conversions
  2020-07-09  7:23                 ` Björn Lundin
@ 2020-07-09  7:49                   ` Dmitry A. Kazakov
  0 siblings, 0 replies; 20+ messages in thread
From: Dmitry A. Kazakov @ 2020-07-09  7:49 UTC (permalink / raw)


On 09/07/2020 09:23, Björn Lundin wrote:
> Den 2020-07-09 kl. 08:20, skrev Dmitry A. Kazakov:
>> On 08/07/2020 21:41, Björn Lundin wrote:
>>
>>> As I replied to Niklas:
>>> It is at least not certain that the number expressed in fixed_type is 
>>> one of them in the array below.
>>
>> The array has varying step 0.01 to 10.0, your test has step 0.001. 
>> What do you expect? Of course it must fail at a very high rate from 
>> 9/1 to 999/1, practically always.
>>
> 
> welll, in practice not always.

Then your test is wrong.

> It only fails when - like my example -
> 
> Fixed_Type(float(5.10)) becomes 5.099

It must, because the conversion truncates and because 5.10 is not the 
machine number stored. You can try this:

    Long_Float'Image (Long_Float (Float (5.10)))

You will not give you 5.10 either. Remember that T'Image rounds the last 
decimal place, so Float'Image (5.10) = " 5.10000E+00" is a lie. " 
5.09999E+00" is a lie too. The choice between these two lies is more or 
less arbitrary (depends on the application).

> and its been running with that construct since 2014,
> and I only noticed now. So - not always, actually very seldom.

You did not say *what* is seldom.

Truncating is no worse than rounding. Actually when dealing with 
integers (fixed-point is a scaled integer) truncating is more natural.

I had a several serious bugs in the past with Ada's rounding integer 
conversions. You must be very careful about these when, for example, 
splitting clock readings into hours, minutes, seconds. A naive 
implementation would seldomly produce wrong results.

Truncating fixed-point conversion is a safer choice. But if you need 
rounding it is there.

> I did expect floating comparison error to go away using fixed type,
> but I forgot about 'garbage in -> garbage out'

It goes away. But you need to eliminate the error first. Eliminating 
error is what conversion does. You move the choice between left and 
right margins of the error interval from comparison into conversion.

> I don't have that kind of rounding errors once the values are converted 
> to fixed_type but I did not realize that I had them in the conversion.

Yes.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de

^ permalink raw reply	[flat|nested] 20+ messages in thread

end of thread, other threads:[~2020-07-09  7:49 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
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
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

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox