10
Some decimal numbers cannot be precisely represented as binary floats due to the internal representation of the binary floats. For example: rounding 14.225 to two decimal digits does not result in 14.23 as one might expect but in 14.22.
Python:
In: round(14.225, 2)
Out: 14.22
Assume, however, that we have a string representation of 14.225 as '14.225', we should be able to achieve our desired rounding '14.23' as a string representation.
This approach can be generalized to arbitrary precision.
Possible Python 2/3 Solution
import sys
def round_string(string, precision):
assert(int(precision) >= 0)
float(string)
decimal_point = string.find('.')
if decimal_point == -1:
if precision == 0:
return string
return string + '.' + '0' * precision
all_decimals = string[decimal_point+1:]
nb_missing_decimals = precision - len(all_decimals)
if nb_missing_decimals >= 0:
if precision == 0:
return string[:decimal_point]
return string + '0' * nb_missing_decimals
if int(all_decimals[precision]) < 5:
if precision == 0:
return string[:decimal_point]
return string[:decimal_point+precision+1]
sign = '-' if string[0] == '-' else ''
integer_part = abs(int(string[:decimal_point]))
if precision == 0:
return sign + str(integer_part + 1)
decimals = str(int(all_decimals[:precision]) + 1)
nb_missing_decimals = precision - len(decimals)
if nb_missing_decimals >= 0:
return sign + str(integer_part) + '.' + '0' * nb_missing_decimals + decimals
return sign + str(integer_part + 1) + '.' + '0' * precision
Usage:
# No IEEE 754 format rounding
In: round_string('14.225',2)
Out: '14.23'
# Trailing zeros
In: round_string('123.4',5)
Out: '123.40000'
In: round_string('99.9',0)
Out: '100'
# Negative values
In: round_string('-99.9',0)
Out: '-100'
In: round_string('1',0)
Out: '1'
# No unnecessary decimal point
In: round_string('1.',0)
Out: '1'
# No unnecessary decimal point
In: round_string('1.0',0)
Out: '1'
In: for i in range(8):
print(round_string('123456789.987654321',i))
Out: 123456790
123456790.0
123456789.99
123456789.988
123456789.9877
123456789.98765
123456789.987654
123456789.9876543
Task
Input argument 1: a string containing
- at least one digit (
0
,1
,2
,3
,4
,5
,6
,7
,8
,9
), - at most one decimal point (
.
) which must be preceded by at least one digit, - an optional minus (
-
) as first character.
Input argument 2: a non-negative integer
Output: the correctly rounded (base 10) string
rounding = Round half away from zero
This is a code-golf. The lowest number of bytes wins!
@KevinCruijssen 1) You do not need to stick to strings in the body of your implementation and are allowed to use built-in rounding. Unfortunately (for the question) the IEEE 754 standard is a widely used standard and thus built-in rounding will not result in the desired behavior. 2) Ok, wasn't aware of the sandbox. – Matthias – 2017-03-17T10:44:42.297
TI-Basic:
round(A,B
5 bytes – Julian Lachniet – 2017-03-17T10:58:45.333@JulianLachniet Actually no, the input number is a string so maybe
round(expr(Str0,B
but then you need to convert that back into a string representation for output. – Timtech – 2017-03-17T11:03:07.6271Regarding the second input argument:
0
is not a positive integer, it is "non-negative". – Stewie Griffin – 2017-03-17T11:04:52.683@Timtech
toString(round(expr(Str0),B
– Julian Lachniet – 2017-03-17T11:06:07.4201I assume we add trailing zeros if needed? Could you perhaps add a test case for
123.4 & 5 --> 123.40000
? Or can we assume the second input will never be larger than the amount of decimals after the point in the first input? – Kevin Cruijssen – 2017-03-17T12:12:24.550@KevinCruijssen Added the example (trailing zeros). Is it possible to make the Python code interactive like Javascript on StackExchange? – Matthias – 2017-03-17T12:29:33.230
1
@Matthias Unless you can integrate the Python with the JavaScript (I've never programmed Python, and barely JS, so I honestly don't know if it's possible) no. But you could always add a Try it online link with your test code. EDIT: Also, it's usually better to wait at least a couple of days until you accept an answer.
– Kevin Cruijssen – 2017-03-17T12:37:38.463@KevinCruijssen Thanks never used TIO before, but very handy. – Matthias – 2017-03-17T12:57:06.017
@JonathanAllan Edit: added rounding explicitly – Matthias – 2017-03-17T13:35:42.780
Related: Round to n Sig Figs
– Neil – 2017-03-17T14:06:52.660Several answers seem to use
printf
and doubles, but they'll all fail with enough digits before or after the decimal dot. Can we assume any size/precision limits for the input? – Dennis – 2017-03-17T14:42:33.470@Dennis: No limitations are specified, so all sizes (Input argument 1) and precision (Input argument 2) sould be supported (as long as your underlying memory system does not become a bottleneck). – Matthias – 2017-03-17T15:02:26.143
Can the inputs be taken in any order? – Business Cat – 2017-03-17T15:27:06.227
For the record, base 10! is an exceedingly odd base to choose. – Jules – 2017-03-17T15:32:04.540
@BasicSunset order is as specified and fixed – Matthias – 2017-03-17T17:18:46.540
@Jules it is base 10. Since the initial solutions just used the default rounding without paying attention to the underlying binary implementation, I added an exclamation mark. But since this is confusing, I will remove it. – Matthias – 2017-03-17T17:20:25.370
Interesting, thanks for the tip @JulianLachniet, didn't notice they added that to the CE calcs. – Timtech – 2017-03-17T17:57:23.433
@Timtech Funny, because I don't have a CE myself ;). This drives my crazy. Also, what is "IEEE" – Julian Lachniet – 2017-03-17T18:50:09.467
@JulianLachniet https://en.wikipedia.org/wiki/IEEE_floating_point
– Timtech – 2017-03-17T18:51:32.237@JulianLachniet IEEE is an organization which specifies a.o. standards such as the IEEE 754 standard for floating points which has a huge impact on hardware and software. Basically it deals with the tradeoff between the number of bits for the mantissa (impacts the precision of the floating point numbers) and exponent (impacts the range of the floating point numbers) – Matthias – 2017-03-17T18:57:40.083
Is
123.4
valid output forround_string('123.4',5)
? Is123456790.
valid output forround_string('123456789.987654321',0)
? – Dennis – 2017-03-18T13:09:12.243@Dennis 1)
round_string('123.4',5)
='123.40000'
2)round_string('123456789.987654321',0)
='123456790'
– Matthias – 2017-03-18T13:17:35.213You should clarify that in your post. Examples do not count as part of the specification. – Dennis – 2017-03-18T13:19:37.190
Also, since we have to support negative numbers, there should be negative number in the test cases, preferably ones that check for correct implementation of round half away from zero. – Dennis – 2017-03-18T13:21:37.027
@Dennis updated – Matthias – 2017-03-18T13:30:16.380
Were you not a bit quick on the accept trigger? – Adám – 2017-03-19T21:20:26.970
@Adám indeed. First thought I needed to manually verify the Wonder version and now there is the APL one which is even shorter. I guess we now reached the limit unless some language has a one byte built-in. – Matthias – 2017-03-20T07:50:57.960
@Matthias APL has a built-in
⍕
, if you allow numeric input. Takes number as right argument and precision as left argument. – Adám – 2017-03-20T07:54:44.873May I suggest you add some test cases? Currently my code works correctly for every single one of your test cases. But it fails on test cases like
987654321.666666666; 7
,987654321.666666666; 8
,987654321.666666666; 9
. – Kevin Cruijssen – 2017-03-20T08:35:33.477@Matthias Can we take input as a number? – Adám – 2017-03-20T10:30:37.317
@Adám only the second argument – Matthias – 2017-03-20T10:33:30.663