Discussion:
float_to_list(X)
Themba Jonga
2021-05-05 15:20:15 UTC
Permalink
Hi All

I have the following situation which I am trying to understand (screenshot
below) ;

- The float N has a number of digits after the decimal point. However
when converted to a list N's value is reduced, albeit by a miniscule amount.
- The contrary is true for the float P which has its' value increased,
also by a tiny amount.

Is there any way to obtain a float_to_list() result which is the exact same
as the original float, where the float variable has an arbitrary number of
decimal places?

[image: image.png]

I am teaching myself Erlang. However I have no formal coding training and I
come from an accounting background.

Regards

*Themba Jonga*


<http://www.avg.com/email-signature?utm_medium=email&utm_source=link&utm_campaign=sig-email&utm_content=webmail>
Virus-free.
www.avg.com
<http://www.avg.com/email-signature?utm_medium=email&utm_source=link&utm_campaign=sig-email&utm_content=webmail>
<#DAB4FAD8-2DD7-40BB-A1B8-4E2AA1F9FDF2>
Jesper Louis Andersen
2021-05-05 16:12:52 UTC
Permalink
Post by Themba Jonga
Hi All
I have the following situation which I am trying to understand (screenshot
below) ;
- The float N has a number of digits after the decimal point. However
when converted to a list N's value is reduced, albeit by a miniscule amount.
- The contrary is true for the float P which has its' value increased,
also by a tiny amount.
Is there any way to obtain a float_to_list() result which is the exact
same as the original float, where the float variable has an arbitrary
number of decimal places?
Floating point numbers are inexact. They use this slight lack of precision
as a means by which computations with them become very fast (because you
have efficient implementations in hardware). However, it means your numbers
as you enter them are slightly off. The numbers you entered are not
representable in the underlying (bit)-representation, so a number close to
the number you entered is chosen, and it is hoped that rounded to fewer
decimal places will account for the inconsistency.

The classic document about IEEE754 floating point arithmetic is this:
https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html -- but it
isn't the most digestible document out there.
A far more approachable guide is: https://floating-point-gui.de/ -- but of
course that might leave out some details you'd like to know.
If you want the background Knuth's "The Art of Computer Programming Vol 2 -
Seminumerical Algorithms" is one of the best expositions I've read on how
they work.
If you want the hardware-centric view, look up books by Hennesey &
Patterson.

As a general advice: getting some familiarity with floating point numbers
is always good. Both in Erlang and other languages.
2***@potatochowder.com
2021-05-05 16:20:01 UTC
Permalink
On 2021-05-05 at 17:20:15 +0200,
Post by Themba Jonga
Hi All
I have the following situation which I am trying to understand (screenshot
below) ;
- The float N has a number of digits after the decimal point. However
when converted to a list N's value is reduced, albeit by a miniscule amount.
- The contrary is true for the float P which has its' value increased,
also by a tiny amount.
Is there any way to obtain a float_to_list() result which is the exact same
as the original float, where the float variable has an arbitrary number of
decimal places?
In short, no. Floating point numbers in computers are inexact, and
nearly all computations (including transformations to and from decimal
notation) involve rounding errors. As an example, how would you (the
person) write the decimal form of 1/3? Remember, computers don't have
an infinite amount of storage for all those threes, but when you
translate any finite number of threes back to a floating point number,
you'll never quite get 1/3. Yes, people can use math tricks to avoid
the problem; equivalent computer and Erlang tricks depend on what,
exactly, you're trying to do.

Much computer science is devoted to this topic; search engines are your
friend, now that you know what you're looking for.
Post by Themba Jonga
[image: image.png]
For short excerpts from a shell, go ahead and copy/paste the actual
text. That way, if necessary, "we" can copy/paste it into our shell
instead of risking errors by having to retype it.
Post by Themba Jonga
I am teaching myself Erlang. However I have no formal coding training
and I come from an accounting background.
For accounting purposes, you may find that using integers (which are
exact) representing pennies (or your smallest unit of currency) work
better than floating point numbers. When it comes time to display them
to a user, then you can insert the appropriate decimal point or comma.
Scott Ribe
2021-05-05 16:37:44 UTC
Permalink
Post by 2***@potatochowder.com
In short, no.
Although many (most, actually nearly all) real numbers cannot be represented precisely as a float, any float can be round-tripped to text and back exactly. This is part of the IEEE floating point standard, actually. (And it's not easy...)
Themba Jonga
2021-05-06 08:54:47 UTC
Permalink
Hi, again.

Following a response I got from Dmitry Klionsky, perhaps it makes sense for
*float_to_list(N)* to be made into a wrapper for
*lists:flatten(io_lib:format("~p",[N]))?*

Eshell V11.1 (abort with ^G)
1> N = 4.4445.
4.4445
2> lists:flatten(io_lib:format("~p",[N])).
"4.4445"
3> P = 5.4443.
5.4443
4> lists:flatten(io_lib:format("~p",[P])).
"5.4443"
5> Q = 1.2345678.
1.2345678
6> lists:flatten(io_lib:format("~p",[Q])).
"1.2345678"
7> float_to_list(Q).
"1.23456779999999999298e+00"
8>

Regards

*Themba Jonga*



<http://www.avg.com/email-signature?utm_medium=email&utm_source=link&utm_campaign=sig-email&utm_content=webmail>
Virus-free.
www.avg.com
<http://www.avg.com/email-signature?utm_medium=email&utm_source=link&utm_campaign=sig-email&utm_content=webmail>
<#m_1222824999368714802_DAB4FAD8-2DD7-40BB-A1B8-4E2AA1F9FDF2>
Post by Scott Ribe
Post by 2***@potatochowder.com
In short, no.
Although many (most, actually nearly all) real numbers cannot be
represented precisely as a float, any float can be round-tripped to text
and back exactly. This is part of the IEEE floating point standard,
actually. (And it's not easy...)
<http://www.avg.com/email-signature?utm_medium=email&utm_source=link&utm_campaign=sig-email&utm_content=webmail>
Virus-free.
www.avg.com
<http://www.avg.com/email-signature?utm_medium=email&utm_source=link&utm_campaign=sig-email&utm_content=webmail>
<#DAB4FAD8-2DD7-40BB-A1B8-4E2AA1F9FDF2>
Richard O'Keefe
2021-05-07 10:26:39 UTC
Permalink
No, making float_to_list/1 a wrapper for format... does not make sense.
float_to_list/1 is meant to give you an accurate representation of the
value. Two different floats, no matter how small the difference,
should result in different lists. It's meant for converting a float
to text that you can send to another machine and reconstitute the
same value there. This will usually result in more digits than a human
would normally want to see.

If you *want* format ~p, use it!

Now perhaps there might be an argument to be made for
float_to_list(X: number(), N: integer()) -> string()
returning a string that represents X as accurately as
possible using N digits. But that is another discussion.
Post by Themba Jonga
Hi, again.
Following a response I got from Dmitry Klionsky, perhaps it makes sense
for *float_to_list(N)* to be made into a wrapper for
*lists:flatten(io_lib:format("~p",[N]))?*
Eshell V11.1 (abort with ^G)
1> N = 4.4445.
4.4445
2> lists:flatten(io_lib:format("~p",[N])).
"4.4445"
3> P = 5.4443.
5.4443
4> lists:flatten(io_lib:format("~p",[P])).
"5.4443"
5> Q = 1.2345678.
1.2345678
6> lists:flatten(io_lib:format("~p",[Q])).
"1.2345678"
7> float_to_list(Q).
"1.23456779999999999298e+00"
8>
Regards
*Themba Jonga*
<http://www.avg.com/email-signature?utm_medium=email&utm_source=link&utm_campaign=sig-email&utm_content=webmail> Virus-free.
www.avg.com
<http://www.avg.com/email-signature?utm_medium=email&utm_source=link&utm_campaign=sig-email&utm_content=webmail>
<#m_-2114829433146319840_m_1222824999368714802_DAB4FAD8-2DD7-40BB-A1B8-4E2AA1F9FDF2>
Post by Scott Ribe
Post by 2***@potatochowder.com
In short, no.
Although many (most, actually nearly all) real numbers cannot be
represented precisely as a float, any float can be round-tripped to text
and back exactly. This is part of the IEEE floating point standard,
actually. (And it's not easy...)
<http://www.avg.com/email-signature?utm_medium=email&utm_source=link&utm_campaign=sig-email&utm_content=webmail> Virus-free.
www.avg.com
<http://www.avg.com/email-signature?utm_medium=email&utm_source=link&utm_campaign=sig-email&utm_content=webmail>
<#m_-2114829433146319840_DAB4FAD8-2DD7-40BB-A1B8-4E2AA1F9FDF2>
Eckard Brauer
2021-05-07 12:00:57 UTC
Permalink
For that purpose it makes maybe more sense to show a sort of "hybrid"
representation of the form floats are usually represented in memory:

s 1.mmmm e xxxx

where

s is signum ("-", "+" or empty),
mmmm is mantissa, in hex, oct or bin to effectively express all
relevant digit positions (with removed trailing zeroes),
xxxx is exponent with possible "-" and also all digits needed.

That would be both human readable and provide some metric, while still
keeping some compactness (maybe not really true for the binary form)
and unambiguousness.

Just my 2 cents.

E.

Am Fri, 7 May 2021 22:26:39 +1200
Post by Richard O'Keefe
Two different floats, no matter how small the difference,
should result in different lists. It's meant for converting a float
to text that you can send to another machine and reconstitute the
same value there.
Scott Ribe
2021-05-07 12:37:44 UTC
Permalink
Post by Eckard Brauer
For that purpose it makes maybe more sense to show a sort of "hybrid"
s 1.mmmm e xxxx
where
s is signum ("-", "+" or empty),
mmmm is mantissa, in hex, oct or bin to effectively express all
relevant digit positions (with removed trailing zeroes),
xxxx is exponent with possible "-" and also all digits needed.
That would be both human readable and provide some metric, while still
keeping some compactness (maybe not really true for the binary form)
and unambiguousness.
Just my 2 cents.
This is not necessary. If float_to_list is meant to transfer values between machines, then it should use the appropriate algorithms and return enough digits to exactly recover the value. Whether it does or does not do that now should probably be documented. If it does not, then perhaps it should be changed, or an option added.
Bob Ippolito
2021-05-07 12:39:00 UTC
Permalink
~p is a lossless format for floats that uses a conservative number of
digits (since R12B02). See OTP-7084. The implementation was based on
mochinum:digits/1 from mochiweb.
Post by Richard O'Keefe
No, making float_to_list/1 a wrapper for format... does not make sense.
float_to_list/1 is meant to give you an accurate representation of the
value. Two different floats, no matter how small the difference,
should result in different lists. It's meant for converting a float
to text that you can send to another machine and reconstitute the
same value there. This will usually result in more digits than a human
would normally want to see.
If you *want* format ~p, use it!
Now perhaps there might be an argument to be made for
float_to_list(X: number(), N: integer()) -> string()
returning a string that represents X as accurately as
possible using N digits. But that is another discussion.
Post by Themba Jonga
Hi, again.
Following a response I got from Dmitry Klionsky, perhaps it makes sense
for *float_to_list(N)* to be made into a wrapper for
*lists:flatten(io_lib:format("~p",[N]))?*
Eshell V11.1 (abort with ^G)
1> N = 4.4445.
4.4445
2> lists:flatten(io_lib:format("~p",[N])).
"4.4445"
3> P = 5.4443.
5.4443
4> lists:flatten(io_lib:format("~p",[P])).
"5.4443"
5> Q = 1.2345678.
1.2345678
6> lists:flatten(io_lib:format("~p",[Q])).
"1.2345678"
7> float_to_list(Q).
"1.23456779999999999298e+00"
8>
Regards
*Themba Jonga*
<http://www.avg.com/email-signature?utm_medium=email&utm_source=link&utm_campaign=sig-email&utm_content=webmail> Virus-free.
www.avg.com
<http://www.avg.com/email-signature?utm_medium=email&utm_source=link&utm_campaign=sig-email&utm_content=webmail>
<#m_4119889666038623623_m_-2114829433146319840_m_1222824999368714802_DAB4FAD8-2DD7-40BB-A1B8-4E2AA1F9FDF2>
Post by Scott Ribe
Post by 2***@potatochowder.com
In short, no.
Although many (most, actually nearly all) real numbers cannot be
represented precisely as a float, any float can be round-tripped to text
and back exactly. This is part of the IEEE floating point standard,
actually. (And it's not easy...)
<http://www.avg.com/email-signature?utm_medium=email&utm_source=link&utm_campaign=sig-email&utm_content=webmail> Virus-free.
www.avg.com
<http://www.avg.com/email-signature?utm_medium=email&utm_source=link&utm_campaign=sig-email&utm_content=webmail>
<#m_4119889666038623623_m_-2114829433146319840_DAB4FAD8-2DD7-40BB-A1B8-4E2AA1F9FDF2>
Thomas Depierre
2021-05-07 11:57:44 UTC
Permalink
That is not true.

The formatting used in format ~p is the shortest round trip one. This will
be different for every single binary floating point number but also be far
shorter and readable. There is work in progress to bring this as an option
in float_to_list/2 thanks to the recent work in Ryu and Dragonbox.

Having a fixed precision already exist in float_to_list/2. This works as
printf %f. I strongly advise to not use it as this precision does not
translate well to the binary format precision loss.

I understand that float to string and string to float conversion are
thought as niche topic, so i will be happy to provide all the bibliography
you may need to explore it if you are surprised by my explanations.

Kindly,

Thomas Depierre
Post by Richard O'Keefe
No, making float_to_list/1 a wrapper for format... does not make sense.
float_to_list/1 is meant to give you an accurate representation of the
value. Two different floats, no matter how small the difference,
should result in different lists. It's meant for converting a float
to text that you can send to another machine and reconstitute the
same value there. This will usually result in more digits than a human
would normally want to see.
If you *want* format ~p, use it!
Now perhaps there might be an argument to be made for
float_to_list(X: number(), N: integer()) -> string()
returning a string that represents X as accurately as
possible using N digits. But that is another discussion.
Post by Themba Jonga
Hi, again.
Following a response I got from Dmitry Klionsky, perhaps it makes sense
for *float_to_list(N)* to be made into a wrapper for
*lists:flatten(io_lib:format("~p",[N]))?*
Eshell V11.1 (abort with ^G)
1> N = 4.4445.
4.4445
2> lists:flatten(io_lib:format("~p",[N])).
"4.4445"
3> P = 5.4443.
5.4443
4> lists:flatten(io_lib:format("~p",[P])).
"5.4443"
5> Q = 1.2345678.
1.2345678
6> lists:flatten(io_lib:format("~p",[Q])).
"1.2345678"
7> float_to_list(Q).
"1.23456779999999999298e+00"
8>
Regards
*Themba Jonga*
<http://www.avg.com/email-signature?utm_medium=email&utm_source=link&utm_campaign=sig-email&utm_content=webmail> Virus-free.
www.avg.com
<http://www.avg.com/email-signature?utm_medium=email&utm_source=link&utm_campaign=sig-email&utm_content=webmail>
<#m_6571645775151075267_m_-2114829433146319840_m_1222824999368714802_DAB4FAD8-2DD7-40BB-A1B8-4E2AA1F9FDF2>
Post by Scott Ribe
Post by 2***@potatochowder.com
In short, no.
Although many (most, actually nearly all) real numbers cannot be
represented precisely as a float, any float can be round-tripped to text
and back exactly. This is part of the IEEE floating point standard,
actually. (And it's not easy...)
<http://www.avg.com/email-signature?utm_medium=email&utm_source=link&utm_campaign=sig-email&utm_content=webmail> Virus-free.
www.avg.com
<http://www.avg.com/email-signature?utm_medium=email&utm_source=link&utm_campaign=sig-email&utm_content=webmail>
<#m_6571645775151075267_m_-2114829433146319840_DAB4FAD8-2DD7-40BB-A1B8-4E2AA1F9FDF2>
Peer Stritzinger
2021-05-08 22:27:15 UTC
Permalink
I think for the sake of the OP "round trip" needs explaining:

It does not mean that “arbitrary float string X” -> float -> “string identical to X” is true.

It does however mean: float Y -> string representation -> float Y.

One problem is that many fractions like e.g. the simple example of decimal 0.1 are representable as a finite binary fraction:

0.1 base 10 is 0.00011001100110011
 base 2 (where 
 means its a infinite repetition of the digits 0011)

So converting seemingly harmless base 10 floating point strings result in infinite binary fractions. Then it depends on how they are rounded if conversion back to base 10 string gives you the same string or a rounding error shows.

Cheers,
-- Peer
Post by Thomas Depierre
That is not true.
The formatting used in format ~p is the shortest round trip one. This will be different for every single binary floating point number but also be far shorter and readable. There is work in progress to bring this as an option in float_to_list/2 thanks to the recent work in Ryu and Dragonbox.
Having a fixed precision already exist in float_to_list/2. This works as printf %f. I strongly advise to not use it as this precision does not translate well to the binary format precision loss.
I understand that float to string and string to float conversion are thought as niche topic, so i will be happy to provide all the bibliography you may need to explore it if you are surprised by my explanations.
Kindly,
Thomas Depierre
No, making float_to_list/1 a wrapper for format... does not make sense.
float_to_list/1 is meant to give you an accurate representation of the
value. Two different floats, no matter how small the difference,
should result in different lists. It's meant for converting a float
to text that you can send to another machine and reconstitute the
same value there. This will usually result in more digits than a human
would normally want to see.
If you *want* format ~p, use it!
Now perhaps there might be an argument to be made for
float_to_list(X: number(), N: integer()) -> string()
returning a string that represents X as accurately as
possible using N digits. But that is another discussion.
Hi, again.
Following a response I got from Dmitry Klionsky, perhaps it makes sense for float_to_list(N) to be made into a wrapper for lists:flatten(io_lib:format("~p",[N]))?
Eshell V11.1 (abort with ^G)
1> N = 4.4445.
4.4445
2> lists:flatten(io_lib:format("~p",[N])).
"4.4445"
3> P = 5.4443.
5.4443
4> lists:flatten(io_lib:format("~p",[P])).
"5.4443"
5> Q = 1.2345678.
1.2345678
6> lists:flatten(io_lib:format("~p",[Q])).
"1.2345678"
7> float_to_list(Q).
"1.23456779999999999298e+00"
8>
Regards
Themba Jonga
<http://www.avg.com/email-signature?utm_medium=email&utm_source=link&utm_campaign=sig-email&utm_content=webmail> Virus-free. www.avg.com <http://www.avg.com/email-signature?utm_medium=email&utm_source=link&utm_campaign=sig-email&utm_content=webmail> <x-msg://10/#m_6571645775151075267_m_-2114829433146319840_m_1222824999368714802_DAB4FAD8-2DD7-40BB-A1B8-4E2AA1F9FDF2>
Post by 2***@potatochowder.com
In short, no.
Although many (most, actually nearly all) real numbers cannot be represented precisely as a float, any float can be round-tripped to text and back exactly. This is part of the IEEE floating point standard, actually. (And it's not easy...)
<http://www.avg.com/email-signature?utm_medium=email&utm_source=link&utm_campaign=sig-email&utm_content=webmail> Virus-free. www.avg.com <http://www.avg.com/email-signature?utm_medium=email&utm_source=link&utm_campaign=sig-email&utm_content=webmail> <x-msg://10/#m_6571645775151075267_m_-2114829433146319840_DAB4FAD8-2DD7-40BB-A1B8-4E2AA1F9FDF2>
Peer Stritzinger
2021-05-08 22:37:35 UTC
Permalink
Just reading that you come from a accounting background: this messiness I described is the reason its a quite bad idea to represent monetary values as floats because its also the reason that:

This is not exactly what was requested by the current tutorial step. Feel free to play with the shell, anyway.
0.1 + 0.1 + 0.1+ 0.1+ 0.1+ 0.1+ 0.1+ 0.1+ 0.1+ 0.1.
0.9999999999999999

No Erlangs floating point implementation isn’t broken (at least not in this way). All floating point implementation based on binary fractions behave like this.

Thats why some languages used for finance have decimal fractions and in languages that don’t the only sane way to represent monetary values are using a integer multiple of some fixed fraction of the currency involved (like pico euro). Its nice if you have a non overflowing integer representation like in Erlang for that BTW.

Now imagine JavaScript has no integers but only floats (if they just added integers recently I take that back partially ;-) and are used to represent money quite a bit -> joy!

Cheers,
-- Peer
It does not mean that “arbitrary float string X” -> float -> “string identical to X” is true.
It does however mean: float Y -> string representation -> float Y.
0.1 base 10 is 0.00011001100110011… base 2 (where … means its a infinite repetition of the digits 0011)
So converting seemingly harmless base 10 floating point strings result in infinite binary fractions. Then it depends on how they are rounded if conversion back to base 10 string gives you the same string or a rounding error shows.
Cheers,
-- Peer
Post by Thomas Depierre
That is not true.
The formatting used in format ~p is the shortest round trip one. This will be different for every single binary floating point number but also be far shorter and readable. There is work in progress to bring this as an option in float_to_list/2 thanks to the recent work in Ryu and Dragonbox.
Having a fixed precision already exist in float_to_list/2. This works as printf %f. I strongly advise to not use it as this precision does not translate well to the binary format precision loss.
I understand that float to string and string to float conversion are thought as niche topic, so i will be happy to provide all the bibliography you may need to explore it if you are surprised by my explanations.
Kindly,
Thomas Depierre
No, making float_to_list/1 a wrapper for format... does not make sense.
float_to_list/1 is meant to give you an accurate representation of the
value. Two different floats, no matter how small the difference,
should result in different lists. It's meant for converting a float
to text that you can send to another machine and reconstitute the
same value there. This will usually result in more digits than a human
would normally want to see.
If you *want* format ~p, use it!
Now perhaps there might be an argument to be made for
float_to_list(X: number(), N: integer()) -> string()
returning a string that represents X as accurately as
possible using N digits. But that is another discussion.
Hi, again.
Following a response I got from Dmitry Klionsky, perhaps it makes sense for float_to_list(N) to be made into a wrapper for lists:flatten(io_lib:format("~p",[N]))?
Eshell V11.1 (abort with ^G)
1> N = 4.4445.
4.4445
2> lists:flatten(io_lib:format("~p",[N])).
"4.4445"
3> P = 5.4443.
5.4443
4> lists:flatten(io_lib:format("~p",[P])).
"5.4443"
5> Q = 1.2345678.
1.2345678
6> lists:flatten(io_lib:format("~p",[Q])).
"1.2345678"
7> float_to_list(Q).
"1.23456779999999999298e+00"
8>
Regards
Themba Jonga
Virus-free. www.avg.com
Post by 2***@potatochowder.com
In short, no.
Although many (most, actually nearly all) real numbers cannot be represented precisely as a float, any float can be round-tripped to text and back exactly. This is part of the IEEE floating point standard, actually. (And it's not easy...)
Virus-free. www.avg.com
Bob Ippolito
2021-05-09 00:05:16 UTC
Permalink
Modern JavaScript does have BigInt. No syntax support though, so it is not
very ergonomic.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt

Many (most?) modern float-to-string functions will use the minimal number
of digits that can represent the float exactly (round-trip without loss of
precision). Erlang's float_to_list/1 is a relic that does not, possibly for
backwards compatibility reasons. I bet changing it would at least break
some brittle tests :) Fortunately the functionality is available in OTP
these days, in a roundabout way.
Post by Peer Stritzinger
Just reading that you come from a accounting background: this messiness I
described is the reason its a quite bad idea to represent monetary values
This is not exactly what was requested by the current tutorial step. Feel
free to play with the shell, anyway.
0.1 + 0.1 + 0.1+ 0.1+ 0.1+ 0.1+ 0.1+ 0.1+ 0.1+ 0.1.
0.9999999999999999
No Erlangs floating point implementation isn’t broken (at least not in
this way). All floating point implementation based on binary fractions
behave like this.
Thats why some languages used for finance have decimal fractions and in
languages that don’t the only sane way to represent monetary values are
using a integer multiple of some fixed fraction of the currency involved
(like pico euro). Its nice if you have a non overflowing integer
representation like in Erlang for that BTW.
Now imagine JavaScript has no integers but only floats (if they just added
integers recently I take that back partially ;-) and are used to represent
money quite a bit -> joy!
Cheers,
-- Peer
It does not mean that “arbitrary float string X” -> float -> “string
identical to X” is true.
It does however mean: float Y -> string representation -> float Y.
One problem is that many fractions like e.g. the simple example of
0.1 base 10 is 0.00011001100110011
 base 2 (where 
 means its a infinite
repetition of the digits 0011)
So converting seemingly harmless base 10 floating point strings result
in infinite binary fractions. Then it depends on how they are rounded if
conversion back to base 10 string gives you the same string or a rounding
error shows.
Cheers,
-- Peer
Post by Thomas Depierre
That is not true.
The formatting used in format ~p is the shortest round trip one. This
will be different for every single binary floating point number but also be
far shorter and readable. There is work in progress to bring this as an
option in float_to_list/2 thanks to the recent work in Ryu and Dragonbox.
Post by Thomas Depierre
Having a fixed precision already exist in float_to_list/2. This works
as printf %f. I strongly advise to not use it as this precision does not
translate well to the binary format precision loss.
Post by Thomas Depierre
I understand that float to string and string to float conversion are
thought as niche topic, so i will be happy to provide all the bibliography
you may need to explore it if you are surprised by my explanations.
Post by Thomas Depierre
Kindly,
Thomas Depierre
No, making float_to_list/1 a wrapper for format... does not make sense.
float_to_list/1 is meant to give you an accurate representation of the
value. Two different floats, no matter how small the difference,
should result in different lists. It's meant for converting a float
to text that you can send to another machine and reconstitute the
same value there. This will usually result in more digits than a human
would normally want to see.
If you *want* format ~p, use it!
Now perhaps there might be an argument to be made for
float_to_list(X: number(), N: integer()) -> string()
returning a string that represents X as accurately as
possible using N digits. But that is another discussion.
Hi, again.
Following a response I got from Dmitry Klionsky, perhaps it makes sense
for float_to_list(N) to be made into a wrapper for
lists:flatten(io_lib:format("~p",[N]))?
Post by Thomas Depierre
Eshell V11.1 (abort with ^G)
1> N = 4.4445.
4.4445
2> lists:flatten(io_lib:format("~p",[N])).
"4.4445"
3> P = 5.4443.
5.4443
4> lists:flatten(io_lib:format("~p",[P])).
"5.4443"
5> Q = 1.2345678.
1.2345678
6> lists:flatten(io_lib:format("~p",[Q])).
"1.2345678"
7> float_to_list(Q).
"1.23456779999999999298e+00"
8>
Regards
Themba Jonga
Virus-free. www.avg.com
Post by 2***@potatochowder.com
In short, no.
Although many (most, actually nearly all) real numbers cannot be
represented precisely as a float, any float can be round-tripped to text
and back exactly. This is part of the IEEE floating point standard,
actually. (And it's not easy...)
Post by Thomas Depierre
Virus-free. www.avg.com
Thomas Depierre
2021-05-09 06:23:17 UTC
Permalink
Small point: float_to_list/2 will get it soon, (OTP25 at most) and i hope
we can make it the default in float_to_list/1.

Something worth pointing out, a lot of these shortest roundtrip without
loss of precision are slightly broken. The main reason it is not present in
most language is that glibc printf cannot do it (no %g is not the same) and
that until fairly recently (2018) it was not known how to make it fast and
not need Big Integers.
Post by Bob Ippolito
Modern JavaScript does have BigInt. No syntax support though, so it is not
very ergonomic.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt
Many (most?) modern float-to-string functions will use the minimal number
of digits that can represent the float exactly (round-trip without loss of
precision). Erlang's float_to_list/1 is a relic that does not, possibly for
backwards compatibility reasons. I bet changing it would at least break
some brittle tests :) Fortunately the functionality is available in OTP
these days, in a roundabout way.
Post by Peer Stritzinger
Just reading that you come from a accounting background: this messiness I
described is the reason its a quite bad idea to represent monetary values
This is not exactly what was requested by the current tutorial step. Feel
free to play with the shell, anyway.
0.1 + 0.1 + 0.1+ 0.1+ 0.1+ 0.1+ 0.1+ 0.1+ 0.1+ 0.1.
0.9999999999999999
No Erlangs floating point implementation isn’t broken (at least not in
this way). All floating point implementation based on binary fractions
behave like this.
Thats why some languages used for finance have decimal fractions and in
languages that don’t the only sane way to represent monetary values are
using a integer multiple of some fixed fraction of the currency involved
(like pico euro). Its nice if you have a non overflowing integer
representation like in Erlang for that BTW.
Now imagine JavaScript has no integers but only floats (if they just
added integers recently I take that back partially ;-) and are used to
represent money quite a bit -> joy!
Cheers,
-- Peer
It does not mean that “arbitrary float string X” -> float -> “string
identical to X” is true.
It does however mean: float Y -> string representation -> float Y.
One problem is that many fractions like e.g. the simple example of
0.1 base 10 is 0.00011001100110011
 base 2 (where 
 means its a
infinite repetition of the digits 0011)
So converting seemingly harmless base 10 floating point strings result
in infinite binary fractions. Then it depends on how they are rounded if
conversion back to base 10 string gives you the same string or a rounding
error shows.
Cheers,
-- Peer
Post by Thomas Depierre
That is not true.
The formatting used in format ~p is the shortest round trip one. This
will be different for every single binary floating point number but also be
far shorter and readable. There is work in progress to bring this as an
option in float_to_list/2 thanks to the recent work in Ryu and Dragonbox.
Post by Thomas Depierre
Having a fixed precision already exist in float_to_list/2. This works
as printf %f. I strongly advise to not use it as this precision does not
translate well to the binary format precision loss.
Post by Thomas Depierre
I understand that float to string and string to float conversion are
thought as niche topic, so i will be happy to provide all the bibliography
you may need to explore it if you are surprised by my explanations.
Post by Thomas Depierre
Kindly,
Thomas Depierre
No, making float_to_list/1 a wrapper for format... does not make sense.
float_to_list/1 is meant to give you an accurate representation of the
value. Two different floats, no matter how small the difference,
should result in different lists. It's meant for converting a float
to text that you can send to another machine and reconstitute the
same value there. This will usually result in more digits than a human
would normally want to see.
If you *want* format ~p, use it!
Now perhaps there might be an argument to be made for
float_to_list(X: number(), N: integer()) -> string()
returning a string that represents X as accurately as
possible using N digits. But that is another discussion.
Hi, again.
Following a response I got from Dmitry Klionsky, perhaps it makes
sense for float_to_list(N) to be made into a wrapper for
lists:flatten(io_lib:format("~p",[N]))?
Post by Thomas Depierre
Eshell V11.1 (abort with ^G)
1> N = 4.4445.
4.4445
2> lists:flatten(io_lib:format("~p",[N])).
"4.4445"
3> P = 5.4443.
5.4443
4> lists:flatten(io_lib:format("~p",[P])).
"5.4443"
5> Q = 1.2345678.
1.2345678
6> lists:flatten(io_lib:format("~p",[Q])).
"1.2345678"
7> float_to_list(Q).
"1.23456779999999999298e+00"
8>
Regards
Themba Jonga
Virus-free. www.avg.com
Post by 2***@potatochowder.com
In short, no.
Although many (most, actually nearly all) real numbers cannot be
represented precisely as a float, any float can be round-tripped to text
and back exactly. This is part of the IEEE floating point standard,
actually. (And it's not easy...)
Post by Thomas Depierre
Virus-free. www.avg.com
Themba Jonga
2021-05-05 17:30:12 UTC
Permalink
Many thanks to all for your prompt and useful responses to my email on the
above subject matter.

Regards
Themba Jonga
Post by Themba Jonga
Hi All
I have the following situation which I am trying to understand (screenshot
below) ;
- The float N has a number of digits after the decimal point. However
when converted to a list N's value is reduced, albeit by a miniscule amount.
- The contrary is true for the float P which has its' value increased,
also by a tiny amount.
Is there any way to obtain a float_to_list() result which is the exact
same as the original float, where the float variable has an arbitrary
number of decimal places?
[image: image.png]
I am teaching myself Erlang. However I have no formal coding training and
I come from an accounting background.
Regards
*Themba Jonga*
<http://www.avg.com/email-signature?utm_medium=email&utm_source=link&utm_campaign=sig-email&utm_content=webmail> Virus-free.
www.avg.com
<http://www.avg.com/email-signature?utm_medium=email&utm_source=link&utm_campaign=sig-email&utm_content=webmail>
<#m_2270170813906058502_DAB4FAD8-2DD7-40BB-A1B8-4E2AA1F9FDF2>
Loading...