## Decimal-fraction precision question

Questions and discussion about running MicroPython on a micro:bit board.
Target audience: MicroPython users with a micro:bit.
MicroGuy
Posts: 15
Joined: Sun Jan 17, 2021 8:31 pm

### Decimal-fraction precision question

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

scruss
Posts: 147
Joined: Sat Aug 12, 2017 2:27 pm
Contact:

### Re: Decimal-fraction precision question

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.

MicroGuy
Posts: 15
Joined: Sun Jan 17, 2021 8:31 pm

### Re: Decimal-fraction precision question

Thank you very much for your insight. The information you provided is very helpful and appreciated. Happy July 4th.

pythoncoder
Posts: 5511
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

### Re: Decimal-fraction precision question

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.
Peter Hinch
Index to my micropython libraries.

scruss
Posts: 147
Joined: Sat Aug 12, 2017 2:27 pm
Contact:

### Re: Decimal-fraction precision question

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

pythoncoder
Posts: 5511
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

### Re: Decimal-fraction precision question

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))``````
Peter Hinch
Index to my micropython libraries.

jimmo
Posts: 2387
Joined: Tue Aug 08, 2017 1:57 am
Location: Sydney, Australia
Contact:

### Re: Decimal-fraction precision question

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!

scruss
Posts: 147
Joined: Sat Aug 12, 2017 2:27 pm