Skip to content

Fix custom float dtype f-string formatting truncating exponent notation#369

Open
xhmelon wants to merge 2 commits intojax-ml:mainfrom
xhmelon:fix-bf16-fmt
Open

Fix custom float dtype f-string formatting truncating exponent notation#369
xhmelon wants to merge 2 commits intojax-ml:mainfrom
xhmelon:fix-bf16-fmt

Conversation

@xhmelon
Copy link
Copy Markdown

@xhmelon xhmelon commented Mar 23, 2026

This PR fixes #341.

Formatting custom float scalars (e.g. bfloat16) would fallback to np.generic.__format__ and be truncated by string length.

python -c "from ml_dtypes import bfloat16; print(f'{bfloat16(1e-6):.8}')"

9.98378e — exponent "-07" truncated

This PR adds a __format__ method to all custom float types that:

  1. Rounds the value to 6 significant digits, which matches the default precision of std::ostringstream from PyCustomFloat_Str/Repr methods.
  2. Delegates to float.__format__ for the actual formatting.

After the fix:

python -c "from ml_dtypes import bfloat16; print(f'{bfloat16(1e-6):.8}')"

9.98378e-07

python -c "from ml_dtypes import bfloat16; print(f'{bfloat16(1e-6):.8e}')"

9.98378000e-07 — padding digits beyond precision with zeros

@google-cla
Copy link
Copy Markdown

google-cla bot commented Mar 23, 2026

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@xhmelon
Copy link
Copy Markdown
Author

xhmelon commented Mar 24, 2026

Hi @jakevdp, would you please activate CI workflows and review this PR?

Copy link
Copy Markdown
Collaborator

@hawkinsp hawkinsp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks the the PR!

// Round to 6 significant digits to match PyCustomFloat_Str/Repr, which
// use std::ostringstream with its default precision of 6. This avoids
// exposing false precision from the float64 expansion.
char buf[14]; // max %.6g output: "-9.98378e+38" + '\0' = 14
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm finding this part strange. For any floating point type, numpy appears to do the following: https://github.com/numpy/numpy/blob/f105cf2d7c20c9829b431c2ae0cdb1f07efaccf2/numpy/_core/src/multiarray/scalartypes.c.src#L633

i.e., convert the type to a python float using nb_format and then call PyObject_Format on the result.

Is there a reason for us to deviate here?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: jnp.bfloat16 f-string formatting truncates exponent

2 participants