20
\$\begingroup\$

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.

\$\endgroup\$
  • 4
    \$\begingroup\$ For Inputs: 520.3, 3, isn't the decimal point in the answer 520. crucial? \$\endgroup\$ – Greg Martin Sep 16 '16 at 18:10
  • 5
    \$\begingroup\$ @GregMartin I believe that it is, as that's the only thing that makes it have 3 sig figs vs. 2 \$\endgroup\$ – Suever Sep 16 '16 at 18:12
  • 3
    \$\begingroup\$ @BetaDecay No it's not. The decimal point would be required for that. \$\endgroup\$ – mbomb007 Sep 16 '16 at 18:16
  • 3
    \$\begingroup\$ "200 is considered to have only ONE significant figure" - chemistry.bd.psu.edu/jircitano/sigfigs.html \$\endgroup\$ – mbomb007 Sep 16 '16 at 18:17
  • 4
    \$\begingroup\$ @DLosc That's why if that was the result you'd actually write it as 2.0 x 10^2, showing the 2 sigfigs. \$\endgroup\$ – mbomb007 Sep 16 '16 at 19:13
3
\$\begingroup\$

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.

\$\endgroup\$
  • \$\begingroup\$ 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) \$\endgroup\$ – Cyoce Sep 19 '16 at 19:13
  • \$\begingroup\$ Also, you can remove the space in import * to make it import* \$\endgroup\$ – Cyoce Sep 19 '16 at 19:18
  • \$\begingroup\$ 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 \$\endgroup\$ – RosLuP Dec 25 '18 at 10:14
  • \$\begingroup\$ @RosLuP: The round() function rounds to n decimal places, not to n significant figures, so it was allowed for this golf event. \$\endgroup\$ – Simon Dec 25 '18 at 21:30
5
\$\begingroup\$

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);
\$\endgroup\$
  • \$\begingroup\$ 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 \$\endgroup\$ – Jörg Hülsermann Sep 19 '16 at 19:59
  • \$\begingroup\$ Ok if not use library round .... \$\endgroup\$ – RosLuP Dec 25 '18 at 10:17
3
\$\begingroup\$

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.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.