I remember someone posting a link to a site that had this compiled executable labelled as an "experimental release", but I can't find it now. Maybe it was it on an IEM page? If you know, please tell me where I could download it from.
-
Pd compiled for double-precision floats and Windows
-
@ddw_music This doesn't invalidate your larger point, but RE double precision floating point on Arduino, that reference is needs updating. I used a MKR Zero because it supports 8 byte doubles. You can see in my code that line 12 reports that the size of a double is 8 bytes, and that line 15 generates 16 correct digits of pi.
For fun I tested c# (which agrees with SC and Pd64) and Java (which agrees with Arduino) so I'm not quite ready to join the "Arduino is wrong" team. I also can't coax Excel into the former camp, but that doesn't mean that it can't be done because I found several examples of how to surface that base 2/base 10 mismatch, e.g. (43.1 - 43.2) + 1.
My apologies to the folks who came here to read about Pd
Edit: Both Java and Arduino display non-zero digits past the 7th digit when 0.1 is stored as a single-precision float, so I find it hard to believe that there's special-purpose code to suppress what I'm gonna refer to from now on as "SuperCollider panic"
-
@jameslo said:
@ddw_music This doesn't invalidate your larger point, but RE double precision floating point on Arduino, that reference is needs updating.
Ok.
For fun I tested c# (which agrees with SC and Pd64) and Java (which agrees with Arduino) so I'm not quite ready to join the "Arduino is wrong" team.
At the end of the day, 0.1 stored as any precision binary fraction doesn't actually equal 0.1, because the denominator of 1/10 includes a prime factor (5) that is not a prime factor of the base (2). If you ask for a decimal string for this imperfect binary representation and you ask for more (decimal) digits than are actually stored, then the trailing digits are by definition fake. They're not real.
"I find it hard to believe that there's special-purpose code to suppress..." but that is exactly what it is: the float-to-string function is supplying junk data, in a way that gives you an illusion of precision. Those zeros (the ones past the precision limit) are all fake. They don't exist in the binary number, so they must be manufactured by the "-to-string" function.
The standard C library way has the advantage of reminding the user that the trailing digits are garbage.
hjh
-
@ddw_music So in the case of c#, Pd64 and SC, are the non-zero numbers past the precision limit real?
-
@jameslo
https://en.wikipedia.org/wiki/Floating-point_arithmetic#Representable_numbers,_conversion_and_rounding"[...] Any rational with a denominator that has a prime factor other than 2 will have an infinite binary expansion. This means that numbers that appear to be short and exact when written in decimal format may need to be approximated when converted to binary floating-point. For example, the decimal number 0.1 is not representable in binary floating-point of any finite precision; the exact binary representation would have a "1100" sequence continuing endlessly:
e = −4; s = 1100110011001100110011001100110011...,
where, as previously, s is the significand and e is the exponent.
When rounded to 24 bits this becomes
e = −4; s = 110011001100110011001101,
which is actually 0.100000001490116119384765625 in decimal. [...]"
And as being said here about SC and Arduino, and on the mailling-list on Max or JSON: Pd is not the only user-friendly (scripting/patching) language/environment that had to deal with this.
Althought backward-compabillity is the most precious thing
and long-term maintaince would become more complicated if PD single and double would differ in such an elementary part, my vote goes for more Pd64 developement, if I had a voice.But for now, it seems like there are several easy experimental improvements, already doable when self-compiling Pd64!?
%.14lg mentioned by @katjav
https://lists.puredata.info/pipermail/pd-list/2012-04/095940.html
or that
http://sourceforge.net/tracker/?func=detail&aid=2952880&group_id=55736&atid=478072Also we could have a look (for %.14lg ) in the code of Katja's Pd-double, and Pd-Spagetties is double, too. (dev stopped, I never tried this)
@jancsika Is Purr-Data double now? https://forum.pdpatchrepo.info/topic/11494/purr-data-double-precision I don't know if or how they care about printing and saving. -
@jameslo said:
@ddw_music So in the case of c#, Pd64 and SC, are the non-zero numbers past the precision limit real?
lacuna beat me to the punch, but I already wrote some stuff up from a slightly different perspective. Maybe this will fill in some gaps.
In short: Yes, those "extra digits" accurately reflect the number that's being stored.
Sticking with single precision... you get 1 sign bit, 8 exponent bits, and 23 mantissa bits (for 24 bits of precision in the mantissa, because in scientific notation, there's one nonzero digit to the left of the point, and in binary, there's only one nonzero digit, so it doesn't have to be encoded).
Binary long division: 1 over 1010 (1010 = decimal 8+2 = decimal 10).
0.00011001100.... __________ 1010 ) 1.0000 - 16/10 1010 ---- 1100 - remainder 6, then add a digit = 12/10 1010 ---- 00100 - remainder 2, then add a digit = 4/10 1000 - 8/10 10000 - 16/10 repeating from here
= 1.10011001100110011001100 * 2^(-4)
The float encoding has a finite number of digits -- therefore it must be a rational number. Moving the binary point 23 places to the right, and compensating in the exponent:
110011001100110011001100 * 2^(-27)
= 0xCCCCCC / 2^27
= 13421772 / 134217728Just to be really pedantic, I went ahead and coded step-by-step decimal long division in SC, and I get:
~longDiv.(13421772, 134217728, maxIter: 50); -> 0.0999999940395355224609375
... which is below the IEEE result. That's because I just naively truncated the mantissa -- I think IEEE's algorithm (when populating the float in the first place, or when dividing) recognizes that the next bit would be 1, and so, rounds up:
~longDiv.(13421773, 134217728, maxIter: 50); -> 0.100000001490116119384765625
... matching lacuna's post exactly.
Division by large powers of two, in decimal, produces a lot of decimal digits below the point -- but it will always terminate.
hjh
-
@lacuna @ddw_music Thank you both for great explanations, and sorry to have made you write and research so much when "yes, it's the actual stored value in decimal, look it up in Wikipedia" would've shut me up . I'll take this up on the forums of those other softwares, now with a much stronger understanding.
-
@jameslo I'm not a native speaker, no offense intended.
Just was hoping, we would overcome those (non)issues, making courageous decisions or find some better workaround/patch/fix.
Some day, I am going to try the mentioned ones. I am learning, too, thank you all!!! -
@lacuna Oh man! In no way was offense taken! I hereby grant everyone the authority to call me out when they think I'm being cranky! I try to use lots of smiley emojis because I learned a long time ago that the way I and my friends talk is probably more snarky and sarcastic than is customary in other parts of the world. To us, it's all just good-natured silliness, us trying to make each other laugh.
The discussion I've been having on the Arduino forum has clarified my thinking a lot, but it's also made clear how the gaps in my education make this a topic that needles a part of my brain. It doesn't help that I'm inbetween music gigs
-
okok wasn't sure if my "as being said" sounded arrogant ... allright!
On the question, how to calculate exact: As far as I understand (not): Fixed point arithmetic can be exact but has no headroom.
-
@lacuna said:
Fixed point arithmetic can be exact...
You and I are on the same wavelength. Someone on the Arduino forum gave me a link to the Arduino printFloat() routine, so I rewrote it in Q4x60 fixed point (i.e. 4 bits of integer, 60 bits of fraction). It now prints out those excess digits correctly. So the issue with their library routine is that it uses doubles to calculate what to print for doubles, which just happens to print zeroes forever past the 10ths place in the case of 0.1 (but not other values, like 1.1). It's a simplistic algorithm due to resource constraints, i.e. why waste limited resources on correctly displaying digits beyond the precision limit? Someone else on the Arduino forum linked to a 15 page academic paper on how hard the fp print problem is--I'm only up to page 4