Round to n Sig Figs

20

1

Challenge

Given a number x and a number n, round number x to n significant figures and output the result.

Significant figures

The significant figures of a number are digits that carry meaning contributing to its measurement resolution. This includes all numbers except leading zeroes.

Bear in mind that leading zeroes after a decimal point are still insignificant figures.

When rounding a digit, you must round away from zero if the following digit is greater or equal than five.

All trailing zeroes after a decimal point are counted as significant.

Input

The first number will be x, the number to be rounded. The second number will be n, the number of significant figures you should round x to.

x will be a number (your code should handle both integers and floating points) between -1,000,000,000 and 1,000, 000,000 inclusive. n will be a positive integer between 1 and 50 inclusive. n will never be greater than the nunber of digits in x.

The input will never be 0 or any form of 0, e.g. 0.000 or 000.

Examples

Inputs: 2.6754, 2
Output: 2.7

An output of 2.7000 would be invalid because the trailing zeroes after the decimal point are counted as significant figures.


Inputs: 0.00034551, 4
Output: 0.0003455

Inputs: 50237.1238, 3
Output: 50200

Note that this must not have a decimal point.


Inputs: 2374905, 1
Output: 2000000

Inputs: 543.0489, 4
Output: 543.0

Inputs: 15, 1
Output: 20

Inputs: 520.3, 3
Output: 520

If you wish, you can output 520. instead but not 520.0.


Inputs: -53.87, 2
Output: -54

Inputs: 0.0999, 2
Output: 0.10

Rules

Built-in functions and libraries which allow you to round a number to n significant figures are disallowed.

Winning

The shortest code in bytes wins.

Beta Decay

Posted 2016-09-16T17:12:51.650

Reputation: 21 478

Yea it looks like that's right, for some reason I was remember incorrectly that leading zeros only applied to the whole number portion. – Suever – 2016-09-16T17:23:01.653

Would 2.7000 be another valid output for 2.6754, 2? – Arnauld – 2016-09-16T17:56:05.137

@Arnauld No, because trailing zeroes are counted as significant figures – Beta Decay – 2016-09-16T18:00:00.017

What's the output for 2.700000000, 5? 2.7000? – mbomb007 – 2016-09-16T18:08:47.160

@mbomb007 Yes, exactly – Beta Decay – 2016-09-16T18:10:02.317

4For Inputs: 520.3, 3, isn't the decimal point in the answer 520. crucial? – Greg Martin – 2016-09-16T18:10:21.323

@GregMartin No, why would it? – Beta Decay – 2016-09-16T18:11:43.180

5@GregMartin I believe that it is, as that's the only thing that makes it have 3 sig figs vs. 2 – Suever – 2016-09-16T18:12:56.230

@Suever I disagree, in 520.3 , the zero is significant, and although it isn't technically significant in 520, it is counted as a sig fig – Beta Decay – 2016-09-16T18:16:05.430

3@BetaDecay No it's not. The decimal point would be required for that. – mbomb007 – 2016-09-16T18:16:29.740

@DLosc 1. Check the question body, 2. No, it isn't valid input – Beta Decay – 2016-09-16T18:16:47.110

3"200 is considered to have only ONE significant figure" - http://chemistry.bd.psu.edu/jircitano/sigfigs.html – mbomb007 – 2016-09-16T18:17:50.907

@mbomb007, sure that may be the actual rules, but this is a simplified version of the problem, intended to be easier for programs to perform – Beta Decay – 2016-09-16T18:18:36.553

@mbomb007 Yet 200 is necessarily ambiguous, as it's also the result of rounding 200.1 to two significant figures. I don't see a problem with allowing it to represent 1-3 sig figs versus 1-2 sig figs. – DLosc – 2016-09-16T18:26:24.163

4@DLosc That's why if that was the result you'd actually write it as 2.0 x 10^2, showing the 2 sigfigs. – mbomb007 – 2016-09-16T19:13:38.897

2Please add a test case for 0.0999, 2. Both of the current answers produce 0.1, but I think it should be 0.10. – DLosc – 2016-09-18T03:52:24.250

@DLosc I've added it – Beta Decay – 2016-09-18T09:57:26.567

Answers

3

Python 3, 83 bytes

(similar to the PHP answer)

from math import *
def s(x,n):
 y=10**(ceil(log10(abs(x)))-n)
 return y*round(x/y)

Test cases:

tests = [(2.6754,2), (0.00034551, 4), (50237.1238, 3),
        (2374905, 1), (543.0489, 4), (15, 1), (520.3, 3), (-53.87, 2)]

print ([s(x,n) for x,n in tests])

Output:

[2.7, 0.0003455, 50200, 2000000, 543.0, 20, 520, -54]

Apart from being slightly longer, another approach that I considered:

from math import *
def s(x,n):
 z=ceil(log10(abs(x)))
 return "%.*f"%(n-z,10**z*round(x/10**z,n))

... produces an incorrect output for the input of (15, 1):

['2.7', '0.0003455', '50200', '2000000', '543.0', '10', '520', '-54']

... due to floating point imprecision in the round() function. It seems likely to me that I could find test cases that would break the "round to zero decimal places" method also if I looked hard enough.

Thus, it seems to me that my solution probably isn't 100% correct for all cases and wouldn't be unless it was computed in decimal. This issue may therefore affect solutions in any language that use FP arithmetic.

Simon

Posted 2016-09-16T17:12:51.650

Reputation: 266

Save some bytes by putting the body of s on the same line, then using semicolons. def s(x,n):y=10**(ceil(log10(abs(x)))-n);return y*round(x/y) – Cyoce – 2016-09-19T19:13:28.620

Also, you can remove the space in import * to make it import* – Cyoce – 2016-09-19T19:18:27.820

your answer for me is not ok because the rules say :"Built-in functions and libraries which allow you to round a number to n significant figures are disallowed." And you use round function with n = 0 – RosLuP – 2018-12-25T10:14:49.807

@RosLuP: The round() function rounds to n decimal places, not to n significant figures, so it was allowed for this golf event. – Simon – 2018-12-25T21:30:17.370

5

PHP, 130 Bytes

<?=number_format($r=round($i=$argv[1],($n=$argv[2])-ceil(log(abs($i),10))),($d=(1+floor(log(abs($r),10))-$n))<0?abs($d):0,".","");

PHP, 133 Bytes works with values <1 for the significant figures

<?=number_format($r=round($i=$argv[1],($n=$argv[2])-floor(log(abs($i),10))-1),($d=(1+floor(log(abs($r),10))-$n))<0?abs($d):0,".","");

PHP, 56 Bytes works but skip unneccessary Zeros

<?=round($i=$argv[1],$argv[2]-floor(log(abs($i),10))-1);

Someone has stolen or deleted the round function in PHP! To make the challenge more interesting. 127 Bytes

<?=ceil($x=($i=$argv[1])*10**(($r=$argv[2])-($l=floor(log(abs($i),10))+1)))-$x<=0.5?ceil($x)*10**($l-$r):floor($x)*10**($l-$r);

Jörg Hülsermann

Posted 2016-09-16T17:12:51.650

Reputation: 13 026

It skips the unnessary Zeros too. It is a version where I use not the native round function in PHP only for joke. It belongs to the 56 Byte Version which I would prefer – Jörg Hülsermann – 2016-09-19T19:59:14.787

Ok if not use library round .... – RosLuP – 2018-12-25T10:17:27.370

3

Batch, 660 652 bytes

@echo off
set m=%1.
set s=
if %m:~,1%==- set s=-&set m=%m:~1%
:m
if %m:~,1%==0 set m=%m:~1%&goto m
set d=%m:.=%
:d
if %d:~,1%==0 set d=%d:~1%&goto d
for /l %%i in (1,1,%2) do call set d=%%d%%0
call set r=%%d:~%2,1%%
call set d=%%d:~,%2%%
if %r% leq 4 goto r
set r=
:i
set/ai=1+%d:~-1%
set r=%i:~-1%%r%
set d=%d:~,-1%
if %i% leq 9 set d=%d%%r%&goto r
if not "%d%"=="" goto i
set d=1%r:~1%
set m=1%m%
set m=%m:1.0=.%
:r
if %m:~,2%==.0 set m=%m:.0=.%&set d=0%d%&goto r
set i=0
set p=.
:l
if %m:~,1%==. echo %s%%i%%p%%d%&exit/b
if %i%==0 set i=
if "%d%"=="" set d=0&set p=
set i=%i%%d:~,1%
set d=%d:~1%
set m=%m:~1%
goto l

Explanation: Starts by suffixing a . to the parameter in case it doesn't have one already, then trims off the sign (which is saved) and any leading zeros. The resulting variable m is saved for later because it will tell us the desired magnitude of the result. Any .s are then removed, which could result in further leading zeros, so they are removed too. n zeros are suffixed to ensure that there are enough digits to round, then the nth and first n digits are extracted. If the nth digit is not 4 or less then we tediously add 1 to the string. If the string overflows then we increase the magnitude by prefixing a 1, but if it was originally less than 0.1 we do that by removing the 1 we just added and also a 0 after the decimal point. If the magnitude is still less than 1 then we copy the zeros after the decimal point to the result, however if it is 1 or more then we extract the integer portion of the answer, adding extra zeros if necessary to reach the decimal point (which is then deleted as it would show incorrect precision). Finally the sign, integer portion, decimal point and decimal portion are concatenated.

Neil

Posted 2016-09-16T17:12:51.650

Reputation: 95 035