September 26, 2020, 06:09:01 am


Own IWBasic 2.x ? -----> Get your free upgrade to 3.x now.........

Rounding to an Arbitrary number of Significant Digits.

Started by GWS, May 13, 2013, 02:00:43 am

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.



Here's a little problem I came across while working on a current project - how to round a number to a given number of significant digits.

That should be easy, I thought.  For example I wanted a number like 12.1257 to return 12.1

After screwing my brains into a knot, I got some clunky code working (which I won't for shame reveal), except to say, it involved a lot of string handling of the Val() to Str$() to Val() type. ::)

How difficult could a simple operation be?

Fortunately, my daughter is an expert Googler, found this discussion in some java - C hieroglyphics, which I think I've managed to translate into the much easier to read Basic code.

Anyway, here's the test program I've concocted, to take any positive, non-zero number, and re-map it to a given number of significant figures.  I was interested in 2 or 3 figures for my application. :)

Code Select

' Rounding to a given number of significant figures ..
' GWS - 2013

autodefine = "off"
setprecision 5

def n:int
def x,r:double

declare Round(value:double,nfigs:int)

' some test values ..
x = 12.1257
'x = 4855600
'x = 2008
'x = 0.0681
'x = .55578
'x = 1.50666
'x = 27460
'x = 635.89

r = Round(x,3)

print "rounded = ",r

do:until inkey$<>""

sub Round(value,nfigs)
def ret,d:double
' routine to round a value to 'n' significant figures ..
if (value = 0)
ret = 0
d = ceil(log10(value))
n = -(d - nfigs)
ret = int(value * 10^n + 0.5) * 10^-n
return ret

Look at that lovely little subroutine - is that smart or what?
I'm still not sure I understand how it does it - but it works!  ;D

If you would like to read the discussion about this, you can find it here ..

All the best, :)

Tomorrow may be too late ..


Hi Graham,

QuoteI'm still not sure I understand how it does it

Code Select
if (value = 0)
This ensures that '0' is not passed to the logarithm function as log(0) is undefined.

Code Select
d = ceil(log10(value))
This returns how many digits there are before the decimal point, using the 'ceil' function to ensure rounding up.
(e.g. log(12.345) is 1.0914911 because it is between 10^1 and 10^2, and this is rounded up to 2)
Values below zero give a negative result for this.

Code Select
n = -(d - nfigs)
('nfigs-d' would probably save a cycle or two)
This calculates how many columns to shift the digits for the purposes of rounding.
(e.g. to find 12.345 to 3 s.f. it should be shifted 1 column to the left to round after the 3)

Code Select
ret = int(value * 10^n + 0.5) * 10^-n
The 'value * 10^n' performs the shift, i.e. turns 12.345 into 123.45
and the 0.5 is added to ensure that the 'int' function rounds anything from .5 and higher upwards.(leaving 123 in the above example)

Finally, the '* 10^-n' reverses the shift.(leaving 12.3 above)

Rather long-winded, but as concise an explanation as I can manage at this time of night.



Thanks Kian,  ;D .. that's a great explanation.

You're right - I should have spotted the double negative ..  'nfigs-d' is much neater  :)

I like that little subroutine - it does all the work in 3 lines, where my sledgehammer method was taking more than a page of code. ::)

All the best, :)

Tomorrow may be too late ..