Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Shouldn't Amount handle decimals formatting with {:.8} ? #2136

Open
RCasatta opened this issue Oct 21, 2023 · 16 comments · Fixed by #2604 · May be fixed by #2682
Open

Shouldn't Amount handle decimals formatting with {:.8} ? #2136

RCasatta opened this issue Oct 21, 2023 · 16 comments · Fixed by #2604 · May be fixed by #2682
Labels
bug C-units PRs modifying the units crate

Comments

@RCasatta
Copy link
Collaborator

I would expect this to work

        assert_eq!("0.00000010 BTC", format!("{:.8}", Amount::from_sat(10)));

While it fails with:

  left: `"0.00000010 BTC"`,
 right: `"0.0000001 BTC"`', bitcoin/src/amount.rs:2379:9
@tcharding
Copy link
Member

Seems like a reasonable expectation.

@Kixunil Kixunil added the bug label Oct 22, 2023
@Kixunil
Copy link
Collaborator

Kixunil commented Oct 22, 2023

Definitely a bug since we intended fully working formatting in Amount.

@yancyribbens
Copy link
Contributor

I had a quick look at this bug, and it seems like the precision is not respected at all:

println!("amount {}", format!("{:.1}", Amount::from_sat(10)));
println!("amount {}", format!("{:.2}", Amount::from_sat(10)));
println!("amount {}", format!("{:.3}", Amount::from_sat(10)));
println!("amount {}", format!("{:.4}", Amount::from_sat(10)));
println!("amount {}", format!("{:.5}", Amount::from_sat(10)));
println!("amount {}", format!("{:.6}", Amount::from_sat(10)));
println!("amount {}", format!("{:.7}", Amount::from_sat(10)));
println!("amount {}", format!("{:.8}", Amount::from_sat(10)));
println!("amount {}", format!("{:.99}", Amount::from_sat(10)));

stdout:

amount 0.0000001 BTC                                                                           
amount 0.0000001 BTC                                                                           
amount 0.0000001 BTC
amount 0.0000001 BTC
amount 0.0000001 BTC
amount 0.0000001 BTC
amount 0.0000001 BTC
amount 0.0000001 BTC
amount 0.0000001 BTC

Also, the tests surrounding this all call macros, which I think could be simplified to helper functions.

@Kixunil
Copy link
Collaborator

Kixunil commented Oct 30, 2023

Oh, now I remembered we purposely ignore precision because it'd cut off significant digits which is pretty bad in a financial application. But cutting zeros should be allowed.

@yancyribbens
Copy link
Contributor

Oh, now I remembered we purposely ignore precision because it'd cut off significant digits which is pretty bad in a financial application.

Hmm well maybe panic or something if precision is used, because silently working may be disastrous if there's an assumption the precision is working.

But cutting zeros should be allowed.

in the bug stated above, it looks like the zero is cut when it should not be.

@Kixunil
Copy link
Collaborator

Kixunil commented Oct 30, 2023

Oh, yeah, maybe panic for precision < 8 to be precise.

in the bug stated above, it looks like the zero is cut when it should not be.

Crap, my mind is broken today, sorry about that!

So yeah - no precision means infinite precision - don't panic, precision 0..8 - panic, precision 8+ - add zeroes.

@RCasatta
Copy link
Collaborator Author

because it'd cut off significant digits which is pretty bad in a financial application

If I ask any spreadsheet to format 0.01 with one decimal it gives me back "0.0" and it's fine.

The use case is putting bitcoin amounts in a text table so that you can read numbers in colums. I can get away with just {:.8} working but maybe someone has space constraint and wants {:.3} the colum total should sum with the underlying sats anyway.

If this is not acceptable, maybe one idea is using the alternate repr for that, eg {:#.3} ?

@apoelstra
Copy link
Member

I agree. Display losing data doesn't mean that the data is actually lost (e.g. in a spreadsheet application).

@Kixunil
Copy link
Collaborator

Kixunil commented Oct 30, 2023

I was thinking about having enable_truncating_decimals method on the builder. What do you think?

@apoelstra
Copy link
Member

I think that's too confusing and undiscoverable. The precision modifier has an expected behavior (which includes dropping data) and we should just follow that behavior.

@Kixunil
Copy link
Collaborator

Kixunil commented Oct 30, 2023

Hmm, I guess you're right.

@Kixunil Kixunil added the C-units PRs modifying the units crate label Jan 27, 2024
448-OG added a commit to 448-OG/rust-bitcoin that referenced this issue Mar 16, 2024
It is common to display bitcoins using trailing zeros upto 8 decimals.
This commit enforces:
- Displaying Amount in BTC with trailing zeroes by eight decimal places
  if the Amount is not precision specified.
- Displaying Amount in BTC upto the precision specified truncating the insignificant
  zeros.
- Displaying amount in BTC without any decimals if the remainder of the amount
  divided by the satoshis in 1 BTC is equal to zero using formula `satoshis.rem_euclid(Amount::ONE_BTC.to_sat()) != 0`

These are not breaking changes and all previous tests pass.

A testcase are also added to for changes introduced.

Resolves: rust-bitcoin#2136
448-OG added a commit to 448-OG/rust-bitcoin that referenced this issue Mar 16, 2024
It is common to display bitcoins using trailing zeros upto 8 decimals.
This commit enforces:
- Displaying Amount in BTC with trailing zeroes by eight decimal places
  if the Amount is not precision specified.
- Displaying Amount in BTC upto the precision specified truncating the insignificant
  zeros.
- Displaying amount in BTC without any decimals if the remainder of the amount
  divided by the satoshis in 1 BTC is equal to zero using formula `satoshis.rem_euclid(Amount::ONE_BTC.to_sat()) != 0`

These are not breaking changes and all previous tests pass.

A testcase are also added to for changes introduced.

Resolves: rust-bitcoin#2136

implement clippy recommendations
448-OG added a commit to 448-OG/rust-bitcoin that referenced this issue Mar 16, 2024
It is common to display bitcoins using trailing zeros upto 8 decimals.
This commit enforces:
- Displaying Amount in BTC with trailing zeroes by eight decimal places
  if the Amount is not precision specified.
- Displaying Amount in BTC upto the precision specified truncating the insignificant
  zeros.
- Displaying amount in BTC without any decimals if the remainder of the amount
  divided by the satoshis in 1 BTC is equal to zero using formula `satoshis.rem_euclid(Amount::ONE_BTC.to_sat()) != 0`

These are not breaking changes and all previous tests pass.

A testcase are also added to for changes introduced.

Resolves: rust-bitcoin#2136
448-OG added a commit to 448-OG/rust-bitcoin that referenced this issue Mar 16, 2024
It is common to display bitcoins using trailing zeros upto 8 decimals.
This commit enforces:
- Displaying Amount in BTC with trailing zeroes by eight decimal places
  if a precision on the Amount is not specified.
- Displaying Amount in BTC upto the precision specified truncating the insignificant zeros.
- Displaying amount in BTC without any decimals if the remainder of the amount
  divided by the satoshis in 1 BTC is equal to zero using formula `satoshis.rem_euclid(Amount::ONE_BTC.to_sat()) != 0`

These are not breaking changes and all previous tests pass.

A testcase is added to for changes introduced.

Resolves: rust-bitcoin#2136
448-OG added a commit to 448-OG/rust-bitcoin that referenced this issue Mar 17, 2024
It is common to display bitcoins using trailing zeros upto 8 decimals.
This commit enforces:
- Displaying Amount in BTC with trailing zeroes by eight decimal places
  if a precision on the Amount is not specified.
- Displaying Amount in BTC upto the precision specified truncating the insignificant zeros.
- Displaying amount in BTC without any decimals if the remainder of the amount
  divided by the satoshis in 1 BTC is equal to zero using formula `satoshis.rem_euclid(Amount::ONE_BTC.to_sat()) != 0`

These are not breaking changes and all previous tests pass.

A testcase is added to for changes introduced.

Resolves: rust-bitcoin#2136
apoelstra added a commit that referenced this issue Mar 17, 2024
d887423 Enforce displaying Amount with trailing zeros (448 OG)

Pull request description:

  It is common to display bitcoins using trailing zeros upto 8 decimals. This commit enforces:
  - Displaying Amount in BTC with trailing zeroes by eight decimal places if a precision on the Amount is not specified.
  - Displaying Amount in BTC upto the precision specified truncating the insignificant zeros.
  - Displaying amount in BTC without any decimals if the remainder of the amount divided by the satoshis in 1 BTC is equal to zero using formula `satoshis.rem_euclid(Amount::ONE_BTC.to_sat()) != 0`

  These are not breaking changes and all previous tests pass.

  A testcase is added to for changes introduced.

  Resolves: #2136

ACKs for top commit:
  sanket1729:
    ACK d887423
  apoelstra:
    ACK d887423

Tree-SHA512: c32e41216477f60a8d95f164bf4a1f6644ea14adc7e169743ce419b0f26ecb6603f3a516f9b18d6508c04ce658f6a0a78ff3b0b062aeb7101b28bbb1e9d522bc
@RCasatta
Copy link
Collaborator Author

#2604 solve the issue as described in the first message.

However, it's not "doing like a spreedsheet" when I ask n digits.

In other words, the following fails:

assert_eq!("0.0 BTC", format!("{:.1}", Amount::from_sat(1)));

@apoelstra
Copy link
Member

Let's re-open the issue. #2604 was by a new contributor who deliberately didn't break any existing tests (which I appreciate) but maybe we need to be more aggressive.

@apoelstra apoelstra reopened this Mar 17, 2024
@448-OG
Copy link
Contributor

448-OG commented Apr 2, 2024

#2604 solve the issue as described in the first message.

However, it's not "doing like a spreedsheet" when I ask n digits.

In other words, the following fails:

assert_eq!("0.0 BTC", format!("{:.1}", Amount::from_sat(1)));

How would this be handled? Would a new method to handle precision with truncating insignificant zeroes suffice? Maybe something like Amount::to_precision()

@apoelstra
Copy link
Member

No, we don't need a new method. The existing fmt method should just handle precision correctly.

@448-OG
Copy link
Contributor

448-OG commented Apr 2, 2024

Thanks! I would like to solve this. Will follow up for more questions if I don't fully understand the task

448-OG added a commit to 448-OG/rust-bitcoin that referenced this issue Apr 13, 2024
All characters beyond the needed precision are truncated

In the case of a SignedAmount the default precision is now 8
just like the Amount

Just like the existing code, no width is added if there exists
fractional values exist just like the existing code works.

Tests have been improved to handle precision

Resolves: rust-bitcoin#2136
@448-OG 448-OG linked a pull request Apr 13, 2024 that will close this issue
448-OG added a commit to 448-OG/rust-bitcoin that referenced this issue Apr 14, 2024
All characters beyond the needed precision are truncated

In the case of a SignedAmount the default precision is now 8
just like the Amount

Replaces self.fmt_value_in() with fmt_satoshi_in() so that
FomartOptions is not made public which would be the requirements
if self.fmt_value_in() is used.

Tests have been improved to handle precision

Resolves: rust-bitcoin#2136
448-OG added a commit to 448-OG/rust-bitcoin that referenced this issue Apr 14, 2024
All characters beyond the needed precision are truncated

In the case of a SignedAmount the default precision is now 8
just like the Amount

Replaces self.fmt_value_in() with fmt_satoshi_in() so that
FomartOptions is not made public which would be the requirements
if self.fmt_value_in() is used.

Tests have been improved to handle precision

Resolves: rust-bitcoin#2136
448-OG added a commit to 448-OG/rust-bitcoin that referenced this issue Apr 14, 2024
All characters beyond the needed precision are truncated

In the case of a SignedAmount the default precision is now 8
just like the Amount

Replaces self.fmt_value_in() with fmt_satoshi_in() so that
FomartOptions is not made public which would be the requirements
if self.fmt_value_in() is used.

Tests have been improved to handle precision

Resolves: rust-bitcoin#2136
448-OG added a commit to 448-OG/rust-bitcoin that referenced this issue Apr 15, 2024
All characters beyond the needed precision are truncated

In the case of a SignedAmount the default precision is now 8
just like the Amount

Replaces self.fmt_value_in() with fmt_satoshi_in() so that
FomartOptions is not made public which would be the requirements
if self.fmt_value_in() is used.

Tests have been improved to handle precision

Resolves: rust-bitcoin#2136
448-OG added a commit to 448-OG/rust-bitcoin that referenced this issue Apr 19, 2024
All characters beyond the needed precision are truncated

In the case of a SignedAmount the default precision is now 8
just like the Amount

Replaces self.fmt_value_in() with fmt_satoshi_in() so that
FomartOptions is not made public which would be the requirements
if self.fmt_value_in() is used.

Tests have been improved to handle precision

Resolves: rust-bitcoin#2136
448-OG added a commit to 448-OG/rust-bitcoin that referenced this issue Apr 19, 2024
All characters beyond the needed precision are truncated

In the case of a SignedAmount the default precision is now 8
just like the Amount

Replaces self.fmt_value_in() with fmt_satoshi_in() so that
FomartOptions is not made public which would be the requirements
if self.fmt_value_in() is used.

Tests have been improved to handle precision

Resolves: rust-bitcoin#2136
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug C-units PRs modifying the units crate
Projects
None yet
7 participants
@yancyribbens @Kixunil @apoelstra @RCasatta @tcharding @448-OG and others