I know floating-point precision is a beast, but... isn't there any sane way to get at, say, the 0.3 part of 4.3?

2,489 views
Skip to first unread message

Philipp Schumann

unread,
Jan 24, 2013, 4:13:04 AM1/24/13
to golan...@googlegroups.com
Here's the problem most easily explained:


I know I can just stringify the float and parse before and after the "." but... yeah wondering if there's some sort of known precision-trick I'm not aware of, or maybe just maybe even some sort of tiny bug in math.Modf()? (Doubt it but...)

Jan Mercl

unread,
Jan 24, 2013, 4:28:50 AM1/24/13
to Philipp Schumann, golang-nuts
From the link

f := 4.3;

// the problem: how to get at 0.3 in f?

It's more or less the same as

s := "4.2999999999999998"

// the problem: how to get at ".3" in s?

A: It's not there: http://play.golang.org/p/MDlErCa7yc

-j

David DENG

unread,
Jan 24, 2013, 4:29:28 AM1/24/13
to golan...@googlegroups.com
The fractional part you got is inaccurate. That's a small inevitable error. A simple way to got an "0.3" text out of the value near it is to limit the number of digits for fractional part. i.e. use %.10v instead of %v.


David

roger peppe

unread,
Jan 24, 2013, 4:49:56 AM1/24/13
to Philipp Schumann, golang-nuts
Why do you care about the exact value?

You can print it out to any degree of precision you like:
http://play.golang.org/p/g4RO7GrbXP

The actual value stored in the float value is not
.3 exactly, because that's not exactly representable.
> --
>
>

Michael Jones

unread,
Jan 24, 2013, 8:36:41 AM1/24/13
to roger peppe, Philipp Schumann, golang-nuts
and this instructive version...
--





--
Michael T. Jones | Chief Technology Advocate  | m...@google.com |  +1 650-335-5765

John Nagle

unread,
Jan 24, 2013, 1:26:19 PM1/24/13
to golan...@googlegroups.com
math.SmallestNonzeroFloat64 is far smaller than 0.0000000000000001.
This is floating point. math.SmallestNonzeroFloat64 is around 5e-324.
You can add math.SmallestNonzeroFloat64 to a number near 1 and
get back the same number you started with.

http://play.golang.org/p/ugEi4eZhmC



bryanturley

unread,
Jan 24, 2013, 3:42:27 PM1/24/13
to golan...@googlegroups.com, itmi...@gmail.com
http://en.wikipedia.org/wiki/Double-precision_floating-point_format#IEEE_754_double-precision_binary_floating-point_format:_binary64

Using unsafe you could extract the exponent and create a bitmask for the would-be integer bits and zero them.
Knowing the exponent and fractional parts you could make a decent guess at how many decimal digits it would be.
I would show you but play.golang.org only plays it safe ;)

I wonder if it would be faster than those conversions...

On Thursday, January 24, 2013 2:33:58 PM UTC-6, itmi...@gmail.com wrote:
How about this? This time with math: http://play.golang.org/p/PoA5fz8AO4

Though, again, no math is needed: http://play.golang.org/p/J34C3-P3zo

The pattern here is that mixing variables with literals: e.g. g := f - 4, results in longer precision.
So, add and subtract to the fractional part you want to test against, the integer part: fint. It makes perfect sense, no?
This will lead to the same longer precision for the test value also, as for the deducted frac value.

Matt Kane's Brain

unread,
Jan 24, 2013, 3:48:44 PM1/24/13
to bryanturley, golan...@googlegroups.com, itmi...@gmail.com
unsafe isn't needed. http://golang.org/pkg/math/#Float64bits
> --
>
>



--
matt kane's brain
http://hydrogenproject.com

bryanturley

unread,
Jan 24, 2013, 4:06:44 PM1/24/13
to golan...@googlegroups.com, itmi...@gmail.com
On Thursday, January 24, 2013 2:48:44 PM UTC-6, mkb wrote:
unsafe isn't needed. http://golang.org/pkg/math/#Float64bits

 
Ooooh sexy

Now that I take the time to look at this in more detail, my example would have looked a lot like

http://golang.org/src/pkg/math/modf.go

So nevermind ;)

On a semi-unrelated note this code has just revealed this headache inducing code
http://play.golang.org/p/efD29937Jh


Matt Kane's Brain

unread,
Jan 24, 2013, 4:10:22 PM1/24/13
to bryanturley, golan...@googlegroups.com, itmi...@gmail.com
"int" is not a keyword!
http://golang.org/ref/spec#Keywords

bryanturley

unread,
Jan 24, 2013, 4:29:02 PM1/24/13
to golan...@googlegroups.com


On Thursday, January 24, 2013 3:10:22 PM UTC-6, mkb wrote:
"int" is not a keyword!
http://golang.org/ref/spec#Keywords


But
http://play.golang.org/p/2K_lBPVoGN

and worse
http://play.golang.org/p/rg4Lz-LY31

go has no operator overloading or method overloading (yay), but it does have conversion almost overloading  O.o

perhaps they should be on a reserved non-keyword list?

bryanturley

unread,
Jan 24, 2013, 4:32:17 PM1/24/13
to golan...@googlegroups.com


On Thursday, January 24, 2013 3:29:02 PM UTC-6, bryanturley wrote:


On Thursday, January 24, 2013 3:10:22 PM UTC-6, mkb wrote:
"int" is not a keyword!
http://golang.org/ref/spec#Keywords


But
http://play.golang.org/p/2K_lBPVoGN

and worse
http://play.golang.org/p/rg4Lz-LY31


Look I gave someone else a headache!
http://play.golang.org/p/GnvdE-otbV

bryanturley

unread,
Jan 24, 2013, 4:58:39 PM1/24/13
to golan...@googlegroups.com, itmi...@gmail.com
On Thursday, January 24, 2013 3:56:57 PM UTC-6, itmi...@gmail.com wrote:
Shadowing anyone?

Well shadowing has never bothered me, but this is a type name that is being redefined.
 

Charlie Dorian

unread,
Jan 24, 2013, 8:14:03 PM1/24/13
to golan...@googlegroups.com
Rather than a rather arbitrary epsilon64, use math.Nextafter. [Usually math.Nextafter(1.0, Inf) is used for epsilon.]

Philipp Schumann

unread,
Jan 25, 2013, 12:56:49 AM1/25/13
to golan...@googlegroups.com
Most above approaches reformulate %v but the following should illustrate much more clearly what the actual problem/use-case is:

Philipp Schumann

unread,
Jan 25, 2013, 1:30:22 PM1/25/13
to golan...@googlegroups.com, itmi...@gmail.com
Haha, OK I guess this is the work-around I'll be using.

Imagine your program sits between two external libs/APIs you have no control over. One expects a version number as two ints (major, minor), the other provides one but as float (as in my example). Bam, there's a use-case where I have very little room for any refactoring.

Now, your solution mindblowingly works. Instead of multiply-by-10, just multiply by 100 then divide by 10... neat-o. Utilizing float precision issues themselves to combat float precision issues, so to speak. Didn't even occur to me it could ever work this way, all I'm painfully aware of is slowly ever-accumulating float error, not self-correcting float error  ;))   I better make DAMN sure I comment in the code why I'm doing this, otherwise some smart-ass (such as: me, 1 or 10 months later) comes along, reads the code and thinks "hey I can streamline this, just multiply by 10 instead".

Nasty edge-cases... don't we love them... anyway, thanks for the brain kickstarter  ;)


On Saturday, January 26, 2013 12:31:16 AM UTC+7, itmi...@gmail.com wrote:
On Friday, January 25, 2013 7:56:49 AM UTC+2, Philipp Schumann wrote:
the following should illustrate much more clearly what the actual problem/use-case is

I don't see any problem ;)
http://play.golang.org/p/9v4W1-hmXN

But I do see how different use cases may look like problems.
Somebody already told you: why do you care so much about the exact value, the precision is yours to command.

Mitică

bryanturley

unread,
Jan 25, 2013, 1:35:32 PM1/25/13
to golan...@googlegroups.com, itmi...@gmail.com


On Friday, January 25, 2013 12:30:22 PM UTC-6, Philipp Schumann wrote:
Haha, OK I guess this is the work-around I'll be using.

Imagine your program sits between two external libs/APIs you have no control over. One expects a version number as two ints (major, minor), the other provides one but as float (as in my example). Bam, there's a use-case where I have very little room for any refactoring.


A library that deals with exact float values?  Sounds like something I would try to avoid.
floats are more stable now but in the past they have been awkwardly unstable between archs.

Reply all
Reply to author
Forward
0 new messages