5
\$\begingroup\$

Overview:

Using you language of choice, implement a complete "half away from 0" rounding function in the shortest amount of code possible.

Rules/Constraints:

  • Direct, predefined Round-like functions are not allowed.
  • Floor/Ceiling-type functions are allowed, if your language supports these.
  • Function shall be able to handle 32-bit floating-point values.
  • Function shall be able to correctly handle negative values (see examples).
  • This is Golf, so shortest code wins.
  • Correct rounding for this challenge is to round away from 0, such that a rounded value will have an equal or larger absolute value.

Input/Output:

  • Your function shall take two parameters:
    • The first is a float x, which is the value to round.
    • The second is an integer n, which is the number of decimal places to round to.
    • x can be a whole number or contain a decimal part, fitting within a 32-bit, single-precision float.
    • n can be greater than or equal to 0, and may be larger than the number of decimal places in x.
  • Output will be the correctly rounded x.
  • *In cases where the solution is not exactly representable in IEEE float format, the output should be the logical representation you would have figured if not using a computer. i.e. The output of Round(0.125, 2) should be 0.13.

Example I/O:

Round(1.23456789, 7)
1.2345679

Round(1.234, 5)
1.234 OR 1.23400 (Your choice on trailing 0)

Round(-0.5, 0)
-1 NOT 0

Round(-0.123, 2)
-0.12 NOT -0.13

Round(3.1415926535897932384626433832, 20)
3.14159265358979323846

Winning:

**Some system limitations may be present which make your function less accurate/usable. In these cases, supply the best possible calculation you can within those limitations.

For example, I have a solution in my preferred environment, VBA in Office 2003, which only allows me to round up to 307 digits, while the IDE will only let me use values up to 15 significant decimal places. (I will eventually post this example here.)

With your answer submission, please post the highest values of n and the largest number of significant decimal digits for x for which your function will run. If you cannot meet the minimum requirements, that solution is disqualified, no matter the code length. (i.e. my own solution described above is invalid)

While this is code golf, and the shortest code will generally win. If two answers exist with different maximum values for x and n, the solution which works with the highest input values (measured as x * n) will win. If these two solutions meet the same limitation while fulfilling the requirements of the challenge, then the shortest code of those two will win.

If no solutions meet the requirement, then the best limitation score (shortest code length in the event of a tie) will win.

Example submission given the rules above for my own code:

<CODE HERE>
Max n = 307
Max x digits = 15
Limitation Score (x * n) = 4605
\$\endgroup\$
  • \$\begingroup\$ Ehm, you say that 15 decimal places is a limitation, and you give examples like 1.23456789, but you also say that it should handle single precision floats. So which one is it? \$\endgroup\$ – Mr Lister Aug 27 '12 at 18:56
  • \$\begingroup\$ @MrLister The spec is to be able to handle Singles. For what I am able to come up with on my own, as an example only, I am personally limited to 15 characters. In other words, my own solution is not valid for this challenge. 1.23456789 is again for example only. \$\endgroup\$ – Gaffi Aug 27 '12 at 18:58
  • 2
    \$\begingroup\$ What is your rounding rule for exact halves? Based on the example of -0.5 it could be away from 0 or nearest odd number; you should make it explicit because a) it's ambiguous; b) those are both weird rules. (The standard rules are half-up, half-down, or half-even). \$\endgroup\$ – Peter Taylor Aug 27 '12 at 19:13
  • \$\begingroup\$ What constitutes "correctly rounded"? \$\endgroup\$ – ardnew Aug 27 '12 at 19:16
  • 2
    \$\begingroup\$ @Gaffi see: en.wikipedia.org/wiki/Rounding#Tie-breaking \$\endgroup\$ – ardnew Aug 27 '12 at 19:24
2
\$\begingroup\$

Q (29 Characters)

{("i"$x*10 xexp y)%10 xexp y}

Sample usage

{("i"$x*10 xexp y)%10 xexp y}[1.23456;4]

Works by multiplying your x input by 10 to the power of your y input, casting to an int and then dividing again by 10 to the power of your y input.

\$\endgroup\$
  • 1
    \$\begingroup\$ Deduplicate for great savings {(6h$x*i)%i:10 xexp y}. \$\endgroup\$ – skeevey Sep 7 '12 at 18:23
1
\$\begingroup\$

Python (153 chars, max(x)=infinite, max(n)=13)

You can input a float, however it works much, much better (max(n)=infinite instead of 13) if you input a string.

def Round(x,n):
    x=map(str,str(x))
    if n==0:x.remove('.')
    n+=1+(n!=0)+(x[0]=='-')
    if n<len(x):x[n-1]=str(int(x[n-1])+(x[n]>='5'))
    return''.join(x[:n])

Explanation:

x=map(str,str(x))
Seperate each character of x. (e.x. when x=5.4, running this makes x equal to ['5', '.', '4'].

if n==0:x.remove('.')
A hack to get around Test Case 3, Round(-0.5, 0). Removes the decimal so we don't get the output -1.

n+=1+(n!=0)+(x[0]=='-')
if n<len(x):x[n-1]=str(int(x[n-1])+(x[n]>='5'))

1 compensates for the decimal point. I think. (n!=0): Compensates for the removal of the decimal point and allows the next line to run.
(x[0]=='-'): Makes it so that in the next line, the negative sign (an additional character) will not mess up the calculation.

if n<len(x): Accounts for Test Case 2, Round(1.234, 5), because Python errors when you try to access the nth item of a list if it's not there. (x[5] is called in the test case, and x does not have a 6th term.)
x[n-1]=str(int(x[n-1])+(x[n]>='5')): Gets the n-1th item of x (which is a string, so it needs to be turned into a number), and adds 1 to it if the nth item of x is greater than or equal to 5. Then it gets turned back into a string.

return''.join(x[:n]): Returns the concatenation of everything up to the nth item in x.

\$\endgroup\$
  • \$\begingroup\$ if n==0:x.remove('.') / A hack to get around Test Case 3, Round(-0.5, 0). Removes the decimal so we don't get the output -1. But we do want -1 as the output for that test case. \$\endgroup\$ – Gaffi Aug 28 '12 at 1:08
  • \$\begingroup\$ In line 4, try replacing n[0]=='-' with x[0]=='-' \$\endgroup\$ – Matt Aug 28 '12 at 1:42
  • \$\begingroup\$ @Gaffi: That's -1., not -1 \$\endgroup\$ – beary605 Aug 28 '12 at 4:50
  • \$\begingroup\$ @Matt: Oops. I originally had my function as Round(a, b), but translated it for clarity. \$\endgroup\$ – beary605 Aug 28 '12 at 4:51
  • \$\begingroup\$ @beary605 Ah, I see. The period is inside the formatted string. :-) \$\endgroup\$ – Gaffi Aug 28 '12 at 10:50
1
\$\begingroup\$

Python, 55 46 chars

R=lambda x,n:int(10**n*x+(.5,-.5)[x<0])/10.**n

Translates the decimal point, rounds half up using int(x+.5), then translates the decimal point back. Negative numbers use int(x-.5).

Should be as accurate as a 64-bit IEEE can get (15+ decimal digits). n can be up to about 300 or so (less if x is big).

\$\endgroup\$
  • \$\begingroup\$ It doesn't work when n=0. R(3.123,0) gives 3.0 instead of 3 \$\endgroup\$ – lortabac Aug 29 '12 at 9:40
  • \$\begingroup\$ I think this should fix the problem (56 chars): R=lambda x,n:int(10**n*x+(.5,-.5)[x<0])/(10.,10)[n<1]**n \$\endgroup\$ – lortabac Aug 29 '12 at 10:04
  • 1
    \$\begingroup\$ @lortabac: I don't understand. 3.0 and 3 are the same number. \$\endgroup\$ – Keith Randall Aug 29 '12 at 15:13
  • \$\begingroup\$ @lortabac: Thanks for the negative number idea. \$\endgroup\$ – Keith Randall Aug 29 '12 at 15:31
  • \$\begingroup\$ Ok, I think you are right. There are no formatting requirements in the rules. \$\endgroup\$ – lortabac Aug 29 '12 at 16:02
1
\$\begingroup\$

C, 51 Characters

float round(float x, int n)
{
    return(long)(x*pow(10,n)+(x>0?0.5:-0.5))/pow(10,n);
}

Not including the function headers, it's 51 characters.

\$\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.