A few stylistic edits to consider. Your code is generally fine. In the example below, I made some minor stylistic
edits: shorter variable names (because they are just as clear in context as the
visually-heavier longer names); direct returns rather than setting number
;
and taking advantage of the built-in round()
function where it applies. I
would also add some explanatory comments to the code, as illustrated below.
It needs some explanation, for reasons discussed below.
def roundToNearestZero(number):
n = abs(number)
if n < 1:
# Find the first non-zero digit.
# We want 3 digits, starting at that location.
s = f'{n:.99f}'
index = re.search('[1-9]', s).start()
return s[:index + 3]
else:
# We want 2 digits after decimal point.
return str(round(n, 2))
The function is unusual. Less convincing is the function itself. First, it's not a rounding operation:
it takes the absolute value, converts to string, and then it does some
rounding-adjacent things. If number
is 1 or larger, the function actually
rounds (to 2 digits past the decimal). Otherwise, the function imposes a floor
operation (to 3 digits, starting at the first non-zero). The whole thing seems
like a conceptual mess, but I understand that you might be operating under some
odd constraints from your project that you cannot easily change.
Choose a better function name. At a minimum you should rename the function. Naming it according to
mathematical operations makes little sense due to its inconsistent and unusual
behavior. Instead you might consider a name oriented toward its purpose: for
example, display_price()
or whatever makes more sense based on its role in
the project.
Data-centric orchestration. Finally, I would encourage you to adopt a more data-centric approach to working
on algorithmic code – while writing code, debugging it, and when asking people
for help. Here I'm talking about the orchestration code rather than the
function itself. The first thing I did when experimenting with your code its to
set up better orchestration:
# This is print-centric. As such, it's not very useful.
print( roundToNearestZero(0.0000001232342) )# 0.000000123
print( roundToNearestZero(1.9333) ) # 1.93
print( roundToNearestZero(-0.00333) ) # 0.00333
print( roundToNearestZero(-123.3333) ) # 123.33
# This is data-centric and thus amenable to efficient testing.
# Any bad edit I made to the code was quickly revealed, and I
# could easily add more test cases as I explored.
def main():
TESTS = (
(0.0000001232342, '0.000000123'),
(1.9333, '1.93'),
(-0.00333, '0.00333'),
(-123.3333, '123.33'),
(0.00000012032342, '0.000000120'),
(-0.00000012032342, '0.000000120'),
(-0.000000120999, '0.000000120'),
(204.947, '204.95'),
)
for inp, exp in TESTS:
got = roundToNearestZero(inp)
if got == exp:
print('ok')
else:
print('FAIL', (inp, got, exp))
abs
in the mix. \$\endgroup\$