Page 1 of 1

Decimal-fraction precision question

Posted: Sat Jul 03, 2021 5:29 pm
by MicroGuy
These two lines:
my_string = str(-0.3470) #Test value
basic.show_string(my_string)

yield the string "-0.347". That trailing zero is important in science and engineering because it indicates accuracy. For example, 0.3 mm is not the same as 0.30 mm. The latter indicates accuracy to a hundredth of a mm. So, it seems MakeCode saves the original value as -0.347, not as -0.3470.

Does MicroPython have a way to set the precision of a floating-point number so the trailing zero becomes part of the value and thus part of the string? Thanks. Happy July 4th. --Jon

Re: Decimal-fraction precision question

Posted: Sat Jul 03, 2021 6:29 pm
by scruss
Sadly, no. I don't know of any (non-symbolic¹) programming language that retains that concept. I haven't seen the "trailing zeros indicate retained precision" convention since I was in grammar school in the 1980s and I've been a mechanical engineer for most of the time since then.

Because of the way that MicroPython stores floating point numbers, it can't even store '-0.3470' exactly. It's probably storing something closer in value to -0.34700000286102294921875 (the four bytes 0xbeb1a9fc: see IEEE-754 Floating Point Converter for details). The vast majority of computer systems work this way.

Most MicroPython ports have integer precision limited only by available memory. If you wish to retain precision, you could store numbers as ratios of two integers: something like -3470 / 10000. Unfortunately, you'd have to write all the code to ensure that all the calculations were done correctly, for as soon as it hits floating point, it's back to weird binary rounding again. The two Python data types that might help here — Decimal and Fraction — are not available for MicroPython.

If you're asking how to represent that number of decimal places, there are various ways to format floating point numbers, such as:

Code: Select all

print('%.4f' % -0.3470 )
-0.3470
but note that this is simple rounding:

Code: Select all

print('%.4f' % -0.34758 )
-0.3476
---
¹: such as maple, mathematica, maxima, etc. I suspect that the charmingly niche language Frink might retain trailing zeros, as it's the sort of thing it would do.

Re: Decimal-fraction precision question

Posted: Sun Jul 04, 2021 4:15 pm
by MicroGuy
Thank you very much for your insight. The information you provided is very helpful and appreciated. Happy July 4th.

Re: Decimal-fraction precision question

Posted: Mon Jul 05, 2021 10:53 am
by pythoncoder
Alternatively (which I find more readable than the string modulus operator):

Code: Select all

print('{:6.3f}'.format(0.3))
The 3 guarantees that three digits will be printed to the right of the decimal point, yielding "0.300". This is the same pretty formatting by a different means and does not contradict the above observations about stored precision.

Re: Decimal-fraction precision question

Posted: Mon Jul 05, 2021 8:34 pm
by scruss
Yes, .format() is probably more readable and recommended these days. I stick to the first thing I learned, so I'm perpetually annoyed that few languages support the one true FORTRAN codes ...

Thinking out loud (= ‘uh-oh, he has no idea what he's doing’) I wonder if working with numbers as strings might help? Entering a literal

Code: Select all

s=-0.3470
on the source will lose any trailing zeroes, but entering

Code: Select all

s="-0.3470"
will retain them. If there is a decimal point in the string s, len(s) - (s.find('.')+1) returns the number of decimal places in the string.

I don't know how to do this with .format(), and this is a not-remotely-useful outline of how to get data-defined precision in MicroPython, but something like:

Code: Select all

print("%*.*f" % (len(s),
                 len(s) - (s.find('.')+1),
                 float(s)))
would reconstruct your numeric string exactly.

Just be careful to remember that Python numbers-as-strings don't do what you might expect, but rather what you'd suspect: s+s returns the rather hilarious '-0.3470-0.3470' instead of the more sensible -0.694

Re: Decimal-fraction precision question

Posted: Tue Jul 06, 2021 5:57 am
by pythoncoder
One way to write programmatic format specifiers:

Code: Select all

x = 5
y = 3
print('{val:{wid}.{dec}f}'.format(val=0.3, wid=x, dec=y))

Re: Decimal-fraction precision question

Posted: Tue Jul 06, 2021 7:29 am
by jimmo
pythoncoder wrote:
Tue Jul 06, 2021 5:57 am
One way to write programmatic format specifiers:

Code: Select all

x = 5
y = 3
print('{val:{wid}.{dec}f}'.format(val=0.3, wid=x, dec=y))
🤯 TIL!

Re: Decimal-fraction precision question

Posted: Wed Nov 03, 2021 11:39 am
by scruss
The OP hasn't checked in since July, but this might have been useful for them: DecimalNumber: floating point arithmetic with arbitrary precision for micropython. It would still require some work to keep track of the trailing zero precision convention, though.