tags:

views:

80

answers:

2

I can round the elements of A to the nearest integers greater than or equal to A

ceil(A)

But what about if I want to round it to the nearest 50 greater than or equal to A?

For example, given the following A array,

A=[24, 35, 78, 101, 199];

A subroutine should return the following

B=Subroutine(A)=[50, 50, 100, 150, 200];
+7  A: 

You could just divide by 50, take ceil(), and multiply by 50 again:

  octave:1> A=[24, 35, 78, 101, 199];
  octave:2> ceil(A)
  ans =

    24    35    78   101   199

  octave:3> 50*(ceil(A/50.))
  ans =

    50    50   100   150   200
Jonathan Dursi
Note that this could conceivably introduce floating-point rounding errors, for large values in A.
Piet Delport
Meh, so get rid of the decimal point after the 50 in the division. Either the numbers are already floating-point values, in which case that issue has already come up elsewhere in the code, or the numbers are integers, in which case just get rid of the decimal point and now you're doing integer division and addition, in which case no floating point issues. So I don't see the problem here.
Jonathan Dursi
The problem is that the results will be incorrect. :-) For example, try `77777777777777777` as input: this method gives the incorrect result `77777777777777792`, while the modulus method correctly gives `77777777777777800`.
Piet Delport
Yes, and so does your method: "a = 77777777777777777; a + mod(-a,50)" also gives 77777777777777792. You may want go look at wikipedia's article on machine epsilon (http://en.wikipedia.org/wiki/Machine_epsilon) and note that you are never going to have numerical operations produce correct results in the 16th decimal place of a floating point number even in double precision. And of course, with (say) 64bit ints, either approach gives the correct result, because 50*ceil(a/50) in integer arithmetic is precisely the same thing as a+mod(-a,50).
Jonathan Dursi
Jonathan: it correctly gives me 77777777777777800 (Octave 3.2). I am familiar with floating point rounding, and that's my whole point: you won't get these rounding integers if you use integer modulus, which is simpler, faster, and exact.
Piet Delport
Addendum: the `ceil` method obviously won't work with integer arithmetic either, which is easy to verify: `A = int64([24, 35, 78, 101, 199]); 50*(ceil(A/50))` gives `0 50 100 100 200`.
Piet Delport
You're right about integer arithmetic, of course; with integer arithmetic you'd want something like ((A+49)/50) rather than using ceil. With floating point (which is what the OP implied by talking about ceil), though, you can never depend on the 17th decimal point, and if your method gets the right answer for to the 17th decimal point number, it's just luck, and for other numbers it won't. Perhaps to demonstrate the point, with octave-3.2.3 on my mac, "format long; a=77777777777777777; a+mod(-a,50)" still gives me "ans = 77777777777777792".
Jonathan Dursi
@Piet and Jonathan: I tested both your answers in MATLAB (what the question asks about) and I got the exact same result from each. However, testing the output with a number like `77777777777777777` doesn't make much sense, since this is a larger integer [than what a double (the default MATLAB type) can hold](http://www.mathworks.com/help/techdoc/ref/bitmax.html). You'd need a 64-bit integer to handle that number.
gnovice
When dealing with floating point nubmers, writing things in terms of integer modulus may well be simpler (that's a question of style), but it isn't -- can't be! -- any more exact. The underlying mod algorithm either uses floating point arithmetic for floating point numbers (eg, using floor() and floating point divide), causing the same problems as any other method, or converts the floating point to an integer, in which case the divide can be done exactly but the conversion will still cause exactly the same imprecision in the final bits.
Jonathan Dursi
If you want to make this interesting, Piet, let's take some agreed upon range of >16 digit floating point numbers, using exactly the same code in octave or matlab or whatever, and see which method gives the right answer most often in this regime - my bet is that there is zero difference, because the question doesn't really make any sense. As gnovice points out above, within the range of applicability, both methods give the same results in their proper range of applicability.
Jonathan Dursi
gnovince: i know 77777777777777777 doesn't fit into a double, and that's the *whole point*: `A = int64([77777777777777777]); A + mod(-A, 50)` *does* give the correct result `77777777777777800`.
Piet Delport
I think we can agree that if the original number *is* an integer, it is much better to keep the computations in integers than convert to floating point and work there, and my offhand comment how to do that was certainly wrong. Either the mod, or the (a+49)/50, would be the way to go. My reading of the question was that the OP was dealing in floats. It's very nice to see @gnovice actually doing something constructive and testing the methods while we just bicker :)
Jonathan Dursi
+2  A: 

An easy way is to just add each number's complement modulo 50:

octave> A = [24, 35, 78, 101, 199] 

octave> mod(-A, 50)       # Complement (mod 50)
ans =

   26   15   22   49    1

octave> A + mod(-A, 50)   # Sum to "next higher" zero (mod 50)
ans =

    50    50   100   150   200

octave> A - mod(A, 50)    # Can also sum to "next lower" zero (mod 50)
ans =

     0     0    50   100   150

(Note that this only depends on integer arithmetic, which avoids errors due to floating-point rounding.)

Piet Delport

related questions