rounding up floating points.

130 views
Skip to first unread message

Bharath M R

unread,
Jun 1, 2012, 2:45:42 AM6/1/12
to sy...@googlegroups.com
Hi,
I was trying to implement interval arithmetic using numpy for plotting. I could not possibly find a way
to **round up** a floating point value. ie sin(<1, 1>) = <0.841, 0.842> rounded to 3 decimals. I would like
to have this functionality because I will always want that a particular value lies in between the intervals.

One way to do this is to convert it into Decimal, quantize with rounding up. ie
Decimal(0.8413).quantize(Decimal('.001'), rounding = 'ROUND_UP'). and convert
back to floating point. The rounding will be used quite regularly, hence converting to
Decimal and converting back will be quite ugly and also inefficient.

Is there any other way to do this?

Thanks,
Bharath M R
 

Chris Smith

unread,
Jun 1, 2012, 3:25:13 AM6/1/12
to sy...@googlegroups.com
On Fri, Jun 1, 2012 at 12:30 PM, Bharath M R <catchmr...@gmail.com> wrote:
> Hi,
> I was trying to implement interval arithmetic using numpy for plotting. I
> could not possibly find a way
> to **round up** a floating point value. ie sin(<1, 1>) = <0.841, 0.842>
> rounded to 3 decimals. I would like

How about round down and then add your interval width?

>>> n=sin(1)
>>> a=n.round(3)
>>> b=(a+10**-3).round(3)
>>> a,b
(0.841, 0.842)

Joachim Durchholz

unread,
Jun 1, 2012, 3:40:50 AM6/1/12
to sy...@googlegroups.com
Am 01.06.2012 09:25, schrieb Chris Smith:
> How about round down and then add your interval width?

You'll add a rounding unit if the input value happens to be exact.

Chris Smith

unread,
Jun 1, 2012, 3:45:15 AM6/1/12
to sy...@googlegroups.com
Can the interval have zero width? If so then, yes, and b could then be
calculated as

b=(a+10**-3).round(3) if a!=n else a

Joachim Durchholz

unread,
Jun 1, 2012, 3:46:57 AM6/1/12
to sy...@googlegroups.com
Am 01.06.2012 08:45, schrieb Bharath M R:
> Hi,
> I was trying to implement interval arithmetic using numpy for plotting. I
> could not possibly find a way
> to **round up** a floating point value.

Use math.ceil.
I.e. multiply with the scale factor, math.ceil, then divide again.

> ie sin(<1, 1>) =<0.841, 0.842>
> rounded to 3 decimals.

On a tangent, for code that uses machine floats/doubles, do not round to
decimals, round to binary digits.
Otherwise, your interval bounds will be inaccurate due to rounding
issues between decimal and binary, making it useless to control
algorithmic inaccuracy.

Bharath M R

unread,
Jun 1, 2012, 3:55:59 AM6/1/12
to sy...@googlegroups.com
round does not necessarily round down. It rounds to the nearest floating point, which can be
greater than the original floating point value and hence might introduce errors into lower bound
of the interval.


Bharath M R

unread,
Jun 1, 2012, 3:58:40 AM6/1/12
to sy...@googlegroups.com


On a tangent, for code that uses machine floats/doubles, do not round to
decimals, round to binary digits.
Otherwise, your interval bounds will be inaccurate due to rounding
issues between decimal and binary, making it useless to control
algorithmic inaccuracy.

 Exactly my problem. Multiplying and using ceil might cause inaccuracy.
Is it possible to round to the nearest floating point value, but rounding up.
Something like `round`, but which always rounds up or rounds down.

Joachim Durchholz

unread,
Jun 1, 2012, 4:00:58 AM6/1/12
to sy...@googlegroups.com
Am 01.06.2012 09:45, schrieb Chris Smith:
> On Fri, Jun 1, 2012 at 1:25 PM, Joachim Durchholz<j...@durchholz.org> wrote:
>> Am 01.06.2012 09:25, schrieb Chris Smith:
>>>
>>> How about round down and then add your interval width?
>>
>> You'll add a rounding unit if the input value happens to be exact.
>>
>
> Can the interval have zero width?

It could, but that doesn't affect the outcome - you're working on the
upper bound.

> If so then, yes, and b could then be
> calculated as
>
> b=(a+10**-3).round(3) if a!=n else a

Not sure what n is here.
Also, you'd want to add half of the step size to cover the round-down case.

I'm not sure what Python's rounding mode is. IEEE defines some rounding
modes that won't do what you expect (such as rounding up or down
depending on the parity of the mantissa - I heard that's helpful to
improve the stability of some numeric algorithm, that's why IEEE defines
it).
The scary thing here is that C code might actually have changed the
rounding mode. And if you're doing numeric work, I'd expect that some
people will indeed use a C module that does exactly this together with
SymPy.

So my proposal would be to stick with floor() and ceil(). These are
well-defined operations.

Aaron Meurer

unread,
Jun 1, 2012, 4:07:28 AM6/1/12
to sy...@googlegroups.com
I should point out that Bharath is using Numpy, so if anyone knows of
a solution using that, that will work too.

Aaron Meurer
> --
> You received this message because you are subscribed to the Google Groups "sympy" group.
> To post to this group, send email to sy...@googlegroups.com.
> To unsubscribe from this group, send email to sympy+un...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/sympy?hl=en.
>

Joachim Durchholz

unread,
Jun 1, 2012, 4:23:03 AM6/1/12
to sy...@googlegroups.com
Am 01.06.2012 09:58, schrieb Bharath M R:
> Exactly my problem. Multiplying and using ceil might cause inaccuracy.
> Is it possible to round to the nearest floating point value, but rounding
> up.
> Something like `round`, but which always rounds up or rounds down.

You seem to be assuming that round(n) is accurate, but is it?
IEEE does not define that function AFAIK.
If that's correct, Python is pretty much forced to do the
multiply-round-divide routine, and may have errors.

It's not even easy to test whether Python is accurate. You'd need some
way to make sure that you test with both the lower and higher machine
number that's around your 0.05-like test value.
I know of no way to reliably produce these from a programming language
(since these produce their constants from a decimal representations and
programming languages usually don't define the conversion rules very
well). You'd probably have to start with a hexadecimal representation of
the double that you want to test. Or construct your test values
algorithmically (that will eliminate coding errors in the hex values,
I'd suggest doing that).

Chris Smith

unread,
Jun 1, 2012, 5:32:26 AM6/1/12
to sy...@googlegroups.com
mpmath.libmp.libmpf has rounding and conversion tools

Are you working with python floats? Will this work:

def interval(f, dec):
m = 10**dec
ff = math.floor(f*m)/m
if f == ff:
return f, f
return ff, ff+1/m

Chris Smith

unread,
Jun 1, 2012, 6:54:28 AM6/1/12
to sy...@googlegroups.com
Or perhaps this is better:

>>> def interval(x,n):
... m=10**-n
... i = int(x/m) # how many m in x?
... a = i*m
... if a == x: return x, x
... return (a, a+m) if x > 0 else (a, a-m)
...
>>> interval(.37512,3)
(0.375, 0.376)
>>> interval(.375,3)
(0.375, 0.375)

krastano...@gmail.com

unread,
Jun 1, 2012, 3:16:45 AM6/1/12
to sy...@googlegroups.com
Not much better, however:

array = np.ceil(1000*array)/1000
> --
> You received this message because you are subscribed to the Google Groups
> "sympy" group.
> To view this discussion on the web visit
> https://groups.google.com/d/msg/sympy/-/k3ijfwq9CL0J.

Chris Smith

unread,
Jun 1, 2012, 7:31:21 AM6/1/12
to sy...@googlegroups.com
On Fri, Jun 1, 2012 at 1:01 PM, krastano...@gmail.com
<krastano...@gmail.com> wrote:
> Not much better, however:
>
> array = np.ceil(1000*array)/1000
>
> On 1 June 2012 08:45, Bharath M R <catchmr...@gmail.com> wrote:
>> Hi,
>> I was trying to implement interval arithmetic using numpy for plotting. I
>> could not possibly find a way
>> to **round up** a floating point value. ie sin(<1, 1>) = <0.841, 0.842>
>> rounded to 3 decimals. I would like

Defining the problem well is important. Do you really want to a) round
up, b) just need the interval, width=1/1000, that contains a given
point, or c) want the interval of width 1/1000 that has the point as
close to the center as possible?

The last routine I sent calculated b, this one calculates c:

def bounds(x, n):
m = 10**-n
a = x - m/2
return a, a+m

>>> bounds(sin(1).n(),3)
(0.840970984807897, 0.841970984807897)

krastano...@gmail.com

unread,
Jun 1, 2012, 8:13:03 AM6/1/12
to sy...@googlegroups.com
My first example was using numpy (as Aaron asked) and uses the
multiply/ceil/divide method as Joachim suggested. For doing plotting I
doubt that higher accuracy is necessary.

Chris Smith

unread,
Jun 1, 2012, 11:24:41 AM6/1/12
to sy...@googlegroups.com
> My first example was using numpy (as Aaron asked) and uses the

(Sorry. I didn't mean to direct the comment to you in particular, I
was just adding to the thread.)

krastano...@gmail.com

unread,
Jun 1, 2012, 11:30:39 AM6/1/12
to sy...@googlegroups.com
:) Don't worry, I did not took it that way. I just noticed that Aaron
was asking for a numpy example and pointed out that it was already
given.

Bharath M R

unread,
Jun 2, 2012, 1:05:32 AM6/2/12
to sy...@googlegroups.com
I will use np.ceil and np.truncate to get it done. Hopefully it won't affect
the plots.

@smichr
I wanted the lower bound to round down and the upper bound to round up.
Something like this.
sin<1, 1.1> = <0.841, 0.892>
I think using the ceil and floor(np.truncate) is the best option.

Reply all
Reply to author
Forward
0 new messages