Asked by Ryan Allan
on 14 Aug 2019

Hi,

Rather than use the fix, floor, ciel functions, I’m trying to create a function to round a number up to a prescribed decimal place.

Eg.

Function roundup_value = ROUNDUP(value, decimalPlaces)

Any help would be greatly appreciated.

Answer by Adam
on 14 Aug 2019

Usual scenario would be to multiply by 10^decimalPlaces, ceil and then divide by 10^decimalPlaces I would imagine.

e.g.

ceil( 1.23456789 * 10^4 ) / 10^4

You could probably use

doc round

with the second argument too, although if you want to enforce always rounding up it likely isn't worth it. I don't know why equivalent versions of ceil and floor don't exist. It was added relatively recently to round rather than in the original implementation, but I would have thought all that family of functions should have been updated the same way.

John D'Errico
on 14 Aug 2019

Adam makes a good point, in that if round was extended as it was, then why did ceil and floor not get the same treatment? My guess is for the same reason I never thought to look to see if ceil and floor had the new capability. It is just something I've never had the slightest desire to do. Yes, I'll suppose a round to n digits has been at times useful, though I think it has been more when I answer a question about exactly that. Personally, I tend not to use it at all.

So why not? Why do I rarely ever use the capability to round a number to tenths, hundreths, etc? I tend not to do so, because I know that it is a fallacy in double precision floating point arithmetic to trust that a number is exactly rounded/truncated/ceiled to the nearest 0.1, or almost any fraction of an integer. (I do trust that Adam knows all this.)

format long g

X = rand(1,3)

X =

0.925425280986515 0.00558112226984153 0.186388406230158

Y = floor(X*10)/10

Y =

0.9 0 0.1

But are they exactly 0.9. 0, and 0.1? Only in the second case are they so.

sprintf('%0.55f',Y(1))

ans =

'0.9000000000000000222044604925031308084726333618164062500'

sprintf('%0.55f',Y(2))

ans =

'0.0000000000000000000000000000000000000000000000000000000'

sprintf('%0.55f',Y(3))

ans =

'0.1000000000000000055511151231257827021181583404541015625'

You can round/ceil/floor a number exactly to a fraction that is a pure power of 2 though. So to round/ceil/floor to the nearest multiple of 1/8, thus a pure power of 2, even though it is a negative power of 2?

Y8 = floor(X*8)/8

Y8 =

0.875 0 0.125

sprintf('%0.55f',Y8(1))

ans =

'0.8750000000000000000000000000000000000000000000000000000'

We can see it is stored as exactly 0.875 too, using my num2bin utility.

num2bin(Y8(1))

ans =

struct with fields:

Class: 'double'

Sign: 1

Exponent: -1

Mantissa: '11100000000000000000000000000000000000000000000000000'

BinaryExpansion: [-1 -2 -3]

BiSci: '1.1100000000000000000000000000000000000000000000000000 B-1'

BiCimal: '0.11100000000000000000000000000000000000000000000000000'

So Y8(1) is EXACTLY represented internally as 1/2 + 1/4 + 1/8 = 0.875.

So, while I accept that floor and ceil arguably should have been extended as was done to round, most of the time, you really are not getting what you asked for anyway.

Sign in to comment.

Opportunities for recent engineering grads.

Apply Today
## 0 Comments

Sign in to comment.