-
Trying to understand precision in Pd
-
Suggest a title for this post>> "trying to understand precision in pd"(the current title is starting to annoy me :P)
-
@dreamer Finally! My intention was to solicit a whole bunch of funny titles and to make the thread playful, but I've obviously failed
Yours wins unless someone posts something funny. -
@jameslo said:
Would [makefilename $.7g] suffice? Or would it have to be .8 or .9 as some argue in this discussion?
%.7gisn't enough, but%.8gseems to catch it.
And for all cases 7 8 or 9, it would mean that there could be different displays of floats that actually equal each other, correct?
Yes, but keep in mind: if you ask C to convert a binary floating-point number to a decimal string with more precision than exists in the original binary, the trailing digits are basically garbage. With
%.9gyou will definitely be able to see that two single precision floats are different, but don't rely on the specific value.For
[==], it's kinda better not to use it at all with fractional floats, unless you're sure the denominator will always be a power of two.[==]might be correct but might sometimes give you false negatives; the absdif approach lets you control the precision that's relevant for equivalence.
hjh
-
@ddw_music said:
%.7gisn't enough, but%.8gseems to catch it.That Fortran discussion I linked to presented the number 1.00000048 as an example of a 9 digit decimal that has a SPFP value that's not representable in 8 decimal digits, but it appears to me that 1.0000005 works fine. How would you prove that 8 digits is sufficient for all SPFP numbers?
-
@jameslo "The glyphosphate tales" (Roundup). "The Monsanto Tales" "The Bayer Tales"...
"Farming Times"......
"Cancer, my tractor and me"...
None good enough so I didn't post...... but maybe on the right track...
Maybe.."The Prisoner" (I am not a number I am a free man).....
If you need precision and 64-bit integer limits give you enough dynamic range then stick with that.
If you need a really massive dynamic range then you will have to put up with floating point imprecision.
I think.....
I suppose that then the question is how to predict the data shift (*/) necessary to fit in the integer range..?
David.
(when I studied Fortran74 I don't remember anyone talking about this problem). -
@whale-av Your titles made me laugh anyway. If it wasn't my thread I would've suggested "horseshoes, hand grenades, and single precision floating point." Or now, maybe "Who is number 0.1? You are number 255"
I was a software engineer for several life sciences and financial services companies and don't remember anything like 255 != 255, but we also had the luxury of more than one numeric datatype and a lot of formatting options.
-
@jameslo said:
That Fortran discussion I linked to...
Sadly I'm not allowed to read it at the moment because I'm on a tablet right now, and "HTML content omitted because you are logged in or using a modern mobile device" (which... I suppose it would make sense that enthusiasts of an outdated language would not favor "modern" devices for reading 🙄 )
presented the number 1.00000048 as an example of a 9 digit decimal that has a SPFP value that's not representable in 8 decimal digits, but it appears to me that 1.0000005 works fine. How would you prove that 8 digits is sufficient for all SPFP numbers?
No idea. At least, the 24 bit mantissa (23 explicit bits plus an implicit 1 left of the binary point) supports 16,777,216 distinct values, which does comprise 8 decimal digits. But there isn't a 1:1 correspondence in digit count when the exponent goes down, e.g. 16 has 2 decimal digits but its inverse 1/16 = 0.0625 = 6.25x10^-2. So there at least is a counterexample showing that 1/x might need more decimal digits than x (as an integer) would.
hjh
-
How about this... in SC:
x = 1.00000048.as32Bits; x.asBinaryString(32).clump(8); -> [00111111, 10000000, 00000000, 00000100]Giving sign bit = 0, exponent = 01111111 and mantissa = (implicit) 1.00000000000000000000100 or 20 zeroes before the trailing 1.
SC doesn't have a primitive to convert a 32-bit float into a string. But it does preserve the mantissa when converting to a 64-bit float (zero-pads the mantissa): sign bit = 0, exponent (11 bits) = 01111111111, mantissa = (implicit) 1.000000000000000000001 (same 20 zeroes, dropping the rest of the 53 mantissa bits) -- therefore the mantissas are equivalent in both 32-bit and 64-bit floats.
y = Float.from32Bits(x); z = [y.high32Bits, y.low32Bits].collect { |b| b.asBinaryString(32).clump(8) }; -> [[00111111, 11110000, 00000000, 00000000], [10000000, 00000000, 00000000, 00000000]] y -> 1.0000004768372 // rounds to 1.00000048So it should be okay to hack the 32-bit by adding to or subtracting from the least significant bits:
x+1= the next possible float for this exponent.[x-2, x-1, x, x+1, x+2].collect(Float.from32Bits(_)) -> [1.0000002384186, 1.0000003576279, 1.0000004768372, 1.0000005960464, 1.0000007152557]... where the difference between subsequent floats ~= 0.0000001192092 or ~= 0.00000012, meaning that at this scale it is not possible for a 32-bit floating point number to represent a different value beginning with 1.0000004. So
%.7g"should" be sufficient (though I wouldn't call myself an expert -- this is an empirical demo, not a proof).hjh
-
@ddw_music I think you mean
%.8gbecause you have to count the leading '1' in [makefilename].Assuming I'm right, this is unfortunately making me feel more strongly about the shortcomings of Pd's number box truncation because 0.1 displays as 0.1 under [makefilename %.8g] whereas the problem in my original post displays as 255.00002. At the very least there ought to be a precision setting in each number box's properties. Like too many things in Pd, it feels perverse to have to tell a new user that in order to display a unique character sequence for a number, you have to turn it into a filename
And gosh, it looks like SC has several numeric datatypes, ways to cast between them, and multiple ways to display each. How profligate! 
-
Hey @alexandros, did you look any further into why [expr ceil($f1)] isn't working on your installation? That seems so odd to me and I'm really curious about it.
-
@jameslo said:
Like too many things in Pd, it feels perverse to have to tell a new user that in order to display a unique character sequence for a number, you have to turn it into a filename

It's a minority case, I guess...? I'm willing to bet that in most cases, a user who summed up 0.1 ten times wants to see "1" and not "1.00001".
And gosh, it looks like SC has several numeric datatypes, ways to cast between them, and multiple ways to display each. How profligate!

SC has 32-bit int (
Integer) and 64-bit float (Float, not Double) in the language side, and the audio side runs on 32-bit floats like Pd audio does. 64-bit floats can be chopped down to 32 bits, but the value is stored as an int and you can't do 32-bit float math on it. But, converting a couple of such ints to double (Float.from32bits) and doing math on them should be (pretty much) the same as single-precision math, except maybe a bit of noise in the LSB.hjh
-
@jameslo I just combined all your patches into one and they all behave like yours! I don't know what was going on earlier, perhaps a typo in [expr]? But I guess it wouldn't have been created. Now the numbers are toggling between 255 and 256 and 0 and 1.5258e-05, like your screenshots.
