rounding fun times
Looks like we have another "feature". Any decimal is automatically rounded to 6 places. Messages, floats, ANYTHING.
Just try and type a decimal longer than 6 places in a messagebox, see what happens
and then try to do [* 1000.] – you should get your decimals right back ;) (at least up to your 32-bits, iirc.)
I could certainly be wrong, but it sounds as if what you’re seeing has to do with floating point representations and the way Max works. If that’s possibly the case, then I would recommend to you Peter Elsea’s explanation (from his tutorial "Max and Numbers"), which remains a touchstone of clarity on this point. And I quote:
"The float data type seems like a familiar sort of number-most of us have been writing decimals since grade school. However, there are some features of the way computers deal with floating point numbers that you should be aware of. Even if a number is shown on the screen as a decimal number, the computer is still working with bits, and has a limited number of them at its disposal. In the case of Max, that’s 32 bits. These are used to represent the infinite range of decimal numbers by a scheme called floating point notation. You may be familiar with a version of this known as scientific notation- to represent 4823, you write 4.823 X 10^4.
To encode floating point numbers, Max follows a convention known as IEEE single precision floating point format. This uses 32 bits as follows:
1 bit to indicate sign (0 for positive)
8 bits for the exponent
23 bits for the significand, which has the form b(sub m).bbbbbbbbbbbbbbbbbbbbbbb where each b is either 1 or 0.
The actual value of the number is ± significand x 2^(exponent)
There is further massaging to save bits or processing time where possible. For instance, the exponent can be positive or negative, but instead of having a sign bit in the exponent, 127 is subtracted from the exponent when the number is converted. With 8 bits, the exponent may range from –127 to 128. In addition b(sub m) is unnecessary since it’s always the same. ( 1 for most numbers, 0 if the exponent is –127.)
The result of all this is that floats can sometimes surprise you. For instance, you cannot represent all possible numbers with this scheme. In fact there are fewer floating point numbers than there are ints. The difference is that while ints are simply limited in magnitude, floats are spotty, jumping from value to value. With large numbers, the jumps can be pretty big, say from 134217712 to 134217720.
With small numbers some odd things happen too. You can see this by stretching a float box, typing in 0, and scrubbing the value up. You’ll see the numbers change by steps of 0.01 up to 1.14, but the next value is 1.149999. That’s because you can’t actually represent 0.01000000000000000 as a binary number times some binary power of two. The value is really something like 0.0099999999999, which will round up to 0.01, but if you keep adding it in, eventually the rounding error catches up with you and 1.149999 pops up."
Is it possible that what you’re seeing is related to this?
Havent gone through Gregory’s entire explanation, but if What Wetterberg says is true that’s actually pretty terrible. It means that if I look at a number I have no way whatsoever of knowing what its actual precision is. Since much of what I do depends on accurate division this is… a problem.
It’s Peter Elsea’s explanation, not mine – *he* deserves the credit for this lucid explanation. Unless I’m misunderstanding you, you appear to be complaining about the fact that 32-bit floating point mathematical representations are not "precise." They never have been on ANY machine or piece of software that works in 32-bits – I’m surprised you’ve never run into this before. It’s one of the reasons that 64-bit numerical calculations are more accurate and desireable in scientific calculations, etc. It’s also what denormalized numbers are all about, and the reason for a hundred billion Max list posts about stuff that "never reaches N" when working with signal values.
It’s everybody’s problem.
Yeah I was about to say, isn’t this just a problem with computers in general.
So one can either say "Well that’s unacceptable!", and go on to create their own computer system without these limitations, or one can say "Isn’t it amazing that we can even do this much with computers?", and proceed to find solutions that work around the limitations inherent to all computer systems.
My guess is one would find the second option a tad more manageable.
Um, no. I know all about floats and macheps and all that fun stuff(not the same but related, I know). My problem is that, if what wettenberg says is true, I cannot look at a message (and god knows what else) to see the precision of the float in question. I could care less about max rounding stuff to the nearest whatever, as long as it is consistent, transparent, and well-documented.
Yes, but, you see, that is in official docs, which is exactly my point. Whereas I had to make a whiny forum post to learn about this situation in max. Hay poquita problema aqui.
If the fora did not exist we would have to invent them =P
For a little more under-the-hood view of Max messages, the "printit" object from CNMAT will show you more detail about what data are being passed around. It’s here: http://cnmat.berkeley.edu/downloads
One goal of the Max environment is to shield users from the underlying implementation details, such as data types. Theoretically, artists can focus more on the art-making and not ever have to consider things like "24-bit manitssa." As you’ve seen, this effort isn’t entirely successful. The needs of efficiency and 20+ years of legacy have left some rough edges. I doubt anybody writing Max from scratch today would recreate the set of compromises that are present in the current environment. Luckily, there is plenty of access to scripting languages in Max — C, java, lisp, lua, clojure, etc — for those times when you really need the control you’re looking for.
In the words of Charlie Papazian: "Relax. Don’t Worry. Have a home-brew."
Shield and poorly document do not have to be synonymous
…it’s actually worse than you think. Type "0.0001234" into a message box.
looks like: "0.000123"
connect to [* 1000.].
save that patch, and re-open.
I agree that this isn’t ok.
Jamesson is working under a fundamental misunderstanding of how numbers work in Max (and, more generally, in all computer software).
Max is not "rounding" anything to some number of decimal places. Max is (necessarily) converting your decimal representation into the binary representation used in essentially *a*l*l* computer software. The display used in flonums, message boxes, [capture], etc., is then a reconversion back into a decimal representation with some number of decimal points.
It probably doesn’t help matters that each of these objects uses a different number of decimal places. But that’s irrelevant.
@Jamesson: you need to RUN, not walk, to Peter Elsea’s tutorial on floating point arithmetic in Max. Do not pass go, do not collect $200, and most certainly do not post until you have read and understood this document:
"It means that if I look at a number I have no way whatsoever of knowing what its actual precision is. Since much of what I do depends on accurate division this is… a problem."
you _do_ always know the precision. it is just not bound to decimal places. ;)
@ Peter castine "… do not post until you have read and understood this document".
The link is not working.
I’ve fixed the link in Peter’s last post. The "Max and Numbers" stuff is here:
Thank you !
Gregory Taylor: I don’t think that op is complaining about how float works.
When I create [* -0.00033939556808664], I get it rounded to [* -0.000339]
But the nearest 32bit float is -3.3939557E-4 so I should be getting [* -0.00033939557].
Which part of that document (you linked to) explains that?
Gregory Taylor: That documents you linked to is about older versions of Max which worked OK. For example, there is object [* 1.059463094] in the document, but if you try to create such object in current version of Max you will see that it’s impossible as it will be automatically rounded to [* 1.059463]. I think that that’s what op meant…
@Gregory Taylor Yes, computers do not process numbers in decimal way, but Max does NOT behave correctly anyway.
This is how "single"==32bit floating point numbers should behave https://www.h-schmidt.net/FloatConverter/IEEE754.html
But Max does round the numbers unnecessarily and in a very strange way. Floating point numbers have exponent, so you can have for example 32bit floating point number representing value of 2.75E-42 (which is 0.00000000000000000000000000000000000000000275) – now try that in Max.
Max shortens everything to 6-7 digits and doesn’t use exponent at all.
Worst thing is, that it evidently used to work OK in some older versions of MAX, like you can see in that "Max&Numbers" document you linked to! For example, there is a [* 0.004032258] object.
I tried creating such object in Max6 and it doesn’t allow me. It rounds it to [* 0.004032] which is not the nearest floating point number.
(and you often really need such precision when doing dsp. for example IIR filters become unstable quickly if you round too much)
OK, thanks to some people in max/msp facebook group I found, that regular max doesn’t truncate the numbers, just doesn’t show them whole. But that is not case for the gen~ where it’s really buggy – when you try to create [* 0.00000143434], it will really trucate it to 0.000001
Workaround for this bug is to use [expr] object instead of [*] in gen~
"I tried creating such object in Max6 and it doesn’t allow me. It rounds it to [* 0.004032] which is not the nearest floating point number."
never trust anything with a version number higher than "4.6.3".
whenever peter c. cant explain it anymore, you know it must be a bug in max.
btw, i think that "float display correction on/off" should be an inspector-controllable attribute per object instance. because sometimes it is cool to use, sometimes not.
ok, one more bug regarding this.
as I mentioned, in regular (non-gen) max the [* 0.004032258] outputs what it should and only the object is displayed truncated to [* 0.004032].
but only until you save your patch!! because max does save only the truncated value and after you reload the patch, the object will be outputing the truncated value.
So it’s totally useless even in non-gen max.
We could perhaps loadbang some mechanism that would rewrite all the values to the full accuracy, or perhaps we just shouldn’t waste our time and money on max and work in some enviroment that works as it should. When I work in max, it’s always 50% of time working on my ideas, then my workflow killed and another 50% time wasted on doing some workarounds.
Forums > MaxMSP