Second argument of round (aNumber)

What does the arguments to the round message do? For instance

3.8.round(100)

outputs just 4. Also the second argument adverb which is the second argument of many other arithmetic messages is not clear to me. Can any one explain this?

No it outputs 0.
It is rounding the the nearest multiple of 100, in this case, 0 * 100.

3.8.round(1)

This outputs 4, as it is rounding to the nearest multiple of 1, in this case, 4 * 1.

Sorry, right I meant 0!

in this case, 0 * 100

Why are you multiplying 0 with 100 (aNumber) here, isn’t the output of 3.8.round 4? As you do below in your second example

in this case, 4 * 1

round rounds to the nearest number you provide in brackets.
Here are some more examples.

3.8.round(0.75) == 3.75 == 5 * 0.75
3.8.round(1) == 4 == 4 * 1
3.8.round(2) == 4 == 2 * 2

Some times the operators are labelled quite poorly in the documentation, whereever the docs say aNumber that should probably be replaced with something more descriptive.
In the case of round it should probably say ‘toTheNearest

I’m sorry, but how do you come up with the 5 in your first example? is the aNumber meant as a multiple of the number which is nearest to it? So in your example we are asking round to give us a result which is a multiple of 0.75 and is also nearest to 3.8. Since 5 x 0.75 is nearer to 3.8 than e.g. 6 x 0.75 we get 5 x 0.75

Is this correct? The round method needs definitely a better documentation :grinning:

It’s really pretty intuitive… try not to overthink it.

The way I think of it is that the second number is a “unit” which, in the rounded number, can’t be broken – a step size. This is really the same as “meant as a multiple factor of the number which is nearest to it” but a little more concrete and easier to visualize.

If it’s .round(2) then imagine units of size 2 on the number line, with an origin = 0 (going both directions, positive and negative). The rounded number must not fall in the middle of a size=2 unit. So it goes to the nearest multiple of 2.

If it’s .round(0.01) then you’d do the same – imagine units of 1/100 on the number line, starting at 0. The rounded number must be on exactly a 1/100 boundary, so the input number will be pulled toward the nearest one.

For what it’s worth, in Pd (and I think Max as well) you have to do the equivalent of trunc(input / aNumber + 0.5) * aNumber, which is a lot of extra work every time you want to ensure a step size constraint. So I really appreciate that James McCartney found a good way to make rounding logic apply in general to every step size.

hjh

Can you explain how you come up with your formula please? It would be more easily expressed as round(input / aNumber) * aNumber. Why are you adding the 0.5 to the quotient?

Can’t do this in Pd because there is no round in Pd.

Ok… so. Let’s say you’re rounding 2.2 in the normal way, to the nearest integer. You don’t have a round operator but you do have a trunc operator.

Where is the dividing line between rounding down vs up?

It’s at the half, something.5.

So to use trunc (where the dividing line is at .0), we need to shift the .5 onto the whole number boundary… which we can do by adding .5.

Does this actually work?

2.2 should round down. 2.2 + 0.5 = 2.7. Truncate off the fractional part and you get 2.0, rounded down, good.

2.6 should round up. 2.6 + 0.5 = 3.1. Truncate off the fractional part and you get 3.0, rounded up, good.

You’ll find that, as long as trunc pulls down, this always works.

Now… what if you want to round to the nearest 10? Trunc in C and in most languages works only at the units place, not at another value. So you have to first scale the calculation from tens to units → divide by 10. Then apply the rounding formula trunc(x + 0.5). Now you have a number that is 1/10th the expected value so scale back to the desired quantization (by multiplying – “undoing” the earlier division).

JMc did make all of this easier in SC by adding a unit size (or quantization) argument to these operators. The underlying calculation is pretty much what I’ve just described though.

hjh

Yes, we ask round to find the nearest multiple of 0.75 from the input (3.8), which results in 3.75, which is 5 × 0.75.

input.round(toTheNearest) == nearestMultipleOfToTheNearest == someInteger * toTheNearest;
3.8.round(0.75) == 3.75 == 5 * 0.75;

These are two different ways of saying the same thing, though… @amt I think the way you said it here is just as valid.

hjh

Oh yes, I misread - I’ll edit my answer

It would be more easily expressed as round(input / aNumber) * aNumber.

Which is exactly the old Smalltalk-80 definition!

roundTo: quantum
	"Answer the nearest number that is a multiple of quantum."
	^(self / quantum) rounded * quantum

Ps. The Sc definition is a bit harder to locate but it’s the same (it also special cases zero so you can modulate the divisor freely):

/// Quantization by rounding. Rounds x to the nearest multiple of quant
inline float sc_round(float x, float quant) { return quant == 0. ? x : sc_floor(x / quant + .5f) * quant; }

Maybe on some machines offset/floor is or was faster than round?