Decimal module output incorrectly displayed in streamlit

Summary

I have a dataframe where one of the columns deals with currency displayed in Euros. Due to the rounding issues I want to use the DECIMAL module to have precise arithmetic outcomes.

  • Python command: 0.1 + 0.2 == 0.3 is FALSE
  • Decimal module: Decimal(β€˜0.1’)+Decimal(β€˜0.2’) == Decimal(β€˜0.3’) is TRUE (This is the scenario I am looking for)

Steps to reproduce

Code snippet Streamlit:

d = {'name': ["A", "B", "C"], 'amount': [0.1, 0.2, 0.3]}
df = pd.DataFrame(data=d)
st.write(df)
for col in df:
    if "amount" in col or "eur" in col:
        df[col] = list(df[col])
        df[col] = [Decimal(str(round(i,2))) for i in df[col]]

#Output dataframe
st.write(df)
#Testing Condition
st.write(df['amount'][0]+df['amount'][1]==df['amount'][2])

Expected behavior:

image

Actual behavior:

image

Amount column is incorrectly displayed at 1, 2 ,3 instead of 0.1, 0.2, 0.3.
Testing condition is correctly represented as true

Hi @Andrea_Farrugia,

Welcome to the forum! :wave:

This is a known bug:

Please upvote the issue :point_up: on GitHub if you want our engineers to prioritize a fix.

The only workarounds until the bug is patched are to either:

  1. Cast the column to numpy.float64 with pd.to_numeric ( A possible problem with to_numeric is that since a Decimal number has arbritary precision, it might not be representable by either integer or float types) or
  2. Cast the column to str

Option 1:

d = {"name": ["A", "B", "C"], "amount": [0.1, 0.2, 0.3]}
df = pd.DataFrame(data=d)
st.write(df)
for col in df:
    if "amount" in col or "eur" in col:
        df[col] = list(df[col])
        df[col] = [Decimal(str(round(i, 2))) for i in df[col]]

# Output dataframe
df.amount = df.amount.apply(pd.to_numeric)
st.write(df)
# Testing Condition
st.write(df["amount"][0] + df["amount"][1] == df["amount"][2]) # Evaluates to False

image

Option 2:

d = {"name": ["A", "B", "C"], "amount": [0.1, 0.2, 0.3]}
df = pd.DataFrame(data=d)
st.write(df)
for col in df:
    if "amount" in col or "eur" in col:
        df[col] = list(df[col])
        df[col] = [Decimal(str(round(i, 2))) for i in df[col]]

# Output dataframe
df.amount = df.amount.apply(str)
st.write(df)
# Testing Condition
st.write(df["amount"][0] + df["amount"][1] == df["amount"][2])

image

1 Like

Thanks a lot for the quick reply. I look at the two options that you posted. Unfortunately, the Testing condition would then be False once the value is changed back to numeric or string.

Sorry for the stupid question but I am still new to github. How can I upvote this issue please?

No worries! Hit the smiley face (:smile:) icon on the top right of the issue and click the thumbs up (:+1:) emoji

Additionally, you could also add a comment to the bottom of the issue, saying you’re running into the bug and a sentence about why a fix is important for your use case:

1 Like

Could you use floats and implement your own rounding for the equality test? Since you are working with currencies the floating point error should always be many orders of magnitude smaller than the precision you need.