Last active
February 9, 2025 19:16
-
-
Save hartwork/9c41958d1d0add5ed76b5f9d58160e21 to your computer and use it in GitHub Desktop.
Demo rounding modes in Python (https://docs.python.org/3/library/decimal.html#rounding-modes)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#! /usr/bin/env python3 | |
# Copyright (c) 2025 Sebastian Pipping <[email protected]> | |
# Licensed under the MIT license | |
import decimal | |
import math | |
import sys | |
from decimal import Decimal | |
import pylab | |
from matplotlib import pyplot | |
PERCENT_FORMAT = "PERCENT_FORMATTING" | |
HUMAN_ROUNDING = decimal.ROUND_HALF_UP | |
NO_DECIMAL_PLACES = Decimal("0") | |
def create_label(rounding_mode: str) -> str: | |
if rounding_mode == decimal.ROUND_HALF_EVEN: | |
return f"Python decimal default (i.e. decimal.{rounding_mode})" | |
elif rounding_mode == HUMAN_ROUNDING: | |
return f"Human default (i.e. decimal.{rounding_mode})" | |
elif rounding_mode == PERCENT_FORMAT: | |
return f"Percent formatting (i.e. decimal.ROUND_HALF_EVEN)" | |
return f"decimal.{rounding_mode}" | |
def values_for_rounding_mode(rounding_mode: str, x_values: list[float]) -> list[float]: | |
if rounding_mode == PERCENT_FORMAT: | |
return [Decimal("%.0f" % x) for x in x_values] | |
with decimal.localcontext(rounding=rounding_mode): | |
return [x.quantize(NO_DECIMAL_PLACES) for x in x_values] | |
if __name__ == '__main__': | |
if sys.version_info < (3, 11): | |
sys.exit("ERROR: Python >=3.11 is needed.") | |
ROUNDING_MODES = [getattr(decimal, k) for k in dir(decimal) if k.startswith('ROUND_')] | |
X = [Decimal(i / 10) for i in range(-20, 20 + 1)] | |
Y_HUMAN = values_for_rounding_mode(decimal.ROUND_HALF_UP, X) | |
for rounding_mode in ROUNDING_MODES + [PERCENT_FORMAT]: | |
Y = values_for_rounding_mode(rounding_mode, X) | |
pyplot.clf() | |
pyplot.grid(visible=True, which='major', axis='both') | |
pyplot.scatter(X, X, label="id(x)", marker='o') | |
if rounding_mode != HUMAN_ROUNDING: # to not plot the the same thing twice | |
pyplot.scatter(X, Y_HUMAN, label=create_label(decimal.ROUND_HALF_UP), marker='o') | |
pyplot.scatter(X, Y, label=create_label(rounding_mode), marker='.') | |
pyplot.legend() | |
filename = f"{rounding_mode.lower()}.svg" | |
print(f"Writing file {filename!r}...") | |
pyplot.savefig(filename) | |
print("Done.") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Expected output
percent_formatting.svg
round_05up.svg
round_ceiling.svg
round_down.svg
round_floor.svg
round_half_down.svg
round_half_even.svg
round_half_up.svg
round_up.svg