# pre-RFC/draft: {:g}, or "floating points for humans"

**URL:** <https://internals.rust-lang.org/t/pre-rfc-draft-g-or-floating-points-for-humans/9110>\
**Category:** Uncategorized\
**Created:** [December 27, 2018, 11:40pm UTC](https://internals.rust-lang.org/t/pre-rfc-draft-g-or-floating-points-for-humans/9110 "2018-12-27T23:40:31Z")\
**Posts on this page:** 15\
**Page:** 1

<div class="post-metadata">

**Author:** ![ExpHP](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/exphp/32/6208_2.png) [@ExpHP](https://internals.rust-lang.org/u/ExpHP)\
**Post date:** [December 27, 2018, 11:40pm UTC](https://internals.rust-lang.org/t/pre-rfc-draft-g-or-floating-points-for-humans/9110/1 "2018-12-27T23:40:32Z")

</div>

**NOTICE:** A final version of this RFC was posted here: [General floating point formatting in Debug with {:g?} by ExpHP · Pull Request #2729 · rust-lang/rfcs · GitHub](https://github.com/rust-lang/rfcs/pull/2729)

* * *

So I've been working on the following RFC, but am starting to run out of steam (and vacation time!) and am not sure if I can finish it. This is a pretty lousy draft, but it's a feature I really want to see in Rust eventually. Hopefully I can get some feedback given what's there, or this can help spark discussion.

* * *

- Feature Name: float\_gen\_fmt
- Start Date: (fill me in with today's date, YYYY-MM-DD)
- RFC PR: (leave this empty)
- Rust Issue: (leave this empty)

# Summary

Add `:g` and `:G` formatting specifiers for floating point numbers, backed by two new traits `std::fmt::{LowerGen,UpperGen}`. These formats dynamically switch between fixed-point formatting and the exponential formats `:e` and `:E` based on the magnitude of a value.

The long-term plan is to allow this flag to be combined with `:?` in a manner like [#2226](https://github.com/rust-lang/rfcs/pull/2226) for recursive formatting of floating point numbers in larger structs---however, this is not included in the current proposal, and is only mentioned for its relevance to the motivation.

# Motivation

Rust currently has two ways to format floating point numbers:

- Simple (through `Debug` and `Display`)
- Exponential (through `LowerExp` and `UpperExp`)

Either of these additionally support a mode of "round-trip precision," when no precision (`.prec`) is provided in the format specifier. However, neither of these two formats are suitable for human-oriented interfaces in contexts where numbers may be of arbitrary magnitude.

The simple formatting scheme can sometimes force the reader to play a game of "count the zeros":

```rust
assert_eq!(
    format!("{:?}", std::f64::MAX),
    "179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0",
);

```

This can frequently be an issue with values like `1e-10`, which may often show up as fuzz factors and tolerances in floating point computations. The only solution offered by the standard library is exponential formatting through `:e` and `:E`, however, exponential format can be taxing for humans to read for values on the order of `1`.

```rust
assert_eq!(format!("{:e}", 22.0), "2.2e1");
assert_eq!(format!("{:e}", 1.0), "1e0");
assert_eq!(format!("{:e}", 0.9), "9e-1");
assert_eq!(format!("{:e}", 0.0), "0e0");

```

Furthermore, this solution cannot be applied to larger structs, and in particular any `Debug` implementors that use the `std::fmt::DebugXyz` family of helpers. (this includes any type that uses `#[derive(Debug)]`)

```rust
#[derive(Debug)]
pub enum StepKind<F> {
    Fixed(F),
    Ulps(u64),
}

#[derive(Debug)]
struct FloatRange<F> {
    min_inclusive: F,
    max_inclusive: F,
    step: StepKind<F>,
}

let positive_normal_f32s = FloatRange {
    min_inclusive: std::f32::MIN_POSITIVE,
    max_inclusive: std::f32::MAX,
    step: StepKind::Ulps(1),
};

// There is no way to print this struct with exponential notation.
assert_eq!(
    format!("{:?}", positive_normal_f32s),
    "FloatRange { min_inclusive: 0.000000000000000000000000000000000000011754944, max_inclusive: 340282350000000000000000000000000000000.0, step: Ulps(1) }",
);

```

Many other languages and utilities have a "general" or "generic" formatting mode which dynamically switches between simple and exponential format, making it useful for a much wider selection of data.

By far, one of the most exceedingly important use cases of human-readable floats is in debug output. But currently, anything using `#[derive(Debug)]` has only one way to print its floats, which is poorly optimized for human readability. With a second future RFC to add support for `"{:g?}"`, users will be able to utilize the existing `Debug` machinery to easily inspect arbitrary data structures with floating point numbers of heterogenous magnitude:

```rust
// using enum-map = "0.4.1"
#[derive(enum_map::Enum, Debug)]
enum Kind { Default, Simple }

#[derive(Debug)]
struct Settings {
    initial: f64,
    step: f64,
}

fn main() {
    let map = enum_map::enum_map!{
        Kind::Default => Settings { initial: 7654.32101234, step: 1e-6 },
        Kind::Simple => Settings { initial: 0.0, step: 0.1 },
    };
    println!("{:g?}", map);
}

```

**Output:**

```rust
{Default: Settings { initial: 7654.32101234, step: 1e-6 }, Simple: Settings { initial: 0, step: 0.1 }}

```

Accomplishing such a feat through an external library is nearly impossible without massive buy-in.

# Guide-level explanation

## Three formatting modes

Rust has three ways to format floating point numbers. These are:

A **simple format** , which is the default:

```rust
assert_eq!(format!("{}", 5.0), "5");
assert_eq!(format!("{}", 5.1), "5.1");
assert_eq!(format!("{}", 1.234e9), "1234000000");
assert_eq!(format!("{}", 1.234e-9), "0.000000001234");

```

An **exponential format** , which always uses scientific notation:

```rust
assert_eq!(format!("{:e}", 5.0), "5e0");
assert_eq!(format!("{:e}", 5.1), "5.1e0");
assert_eq!(format!("{:e}", 1.234e9), "1.234e9");
assert_eq!(format!("{:e}", 1.234e-9), "1.234e-9");
assert_eq!(format!("{:E}", 1.234e-9), "1.234E-9");

```

And a **general format** , which switches between simple and exponential based on magnitude:

```rust
assert_eq!(format!("{:g}", 5.0), "5");
assert_eq!(format!("{:g}", 5.1), "5.1");
assert_eq!(format!("{:g}", 1.234e9), "1.234e9");
assert_eq!(format!("{:g}", 1.234e-9), "1.234e-9");
assert_eq!(format!("{:G}", 1.234e-9), "1.234E-9");

```

## Precision

All three of the above formats print to round-trip precision by default. This can be changed by adding a precision to the format specifier (e.g. `.4`). When a precision is added to either the simple or exponential format, the output will always contain that many digits after the decimal point:

```rust
assert_eq!(format!("{:.4}", 5.1), "5.1000");
assert_eq!(format!("{:.4e}", 1.234e9), "1.2340e9");

```

When a precision is added to the general format, it is used as the _maximum_ number of significant figures to display. It is also used as the maximum number of digits that large numbers are allowed to contain before they are switched to exponential format. Not only does this give you control over the threshold for exponential format, but it also prevents a number like `1234.0` from being formatted as `1230`. The threshold for small numbers remains fixed.

```rust
assert_eq!(format!("{:.3g}", 500.0), "500");
assert_eq!(format!("{:.3g}", 5000.0), "5e3");
assert_eq!(format!("{:.3g}", 1.234e9), "1.23e9");

```

# Reference-level explanation

## Changes to the compiler and standard library

Two traits are added to `core::fmt` and `std::fmt`:

```rust
/// `g` formatting.
pub trait LowerGen {
    fn fmt(&self, f: &mut Formatter) -> Result;
}

/// `G` formatting.
pub trait UpperGen {
    fn fmt(&self, f: &mut Formatter) -> Result;
}

// Implementations matching those of LowerExp and UpperExp
impl LowerGen for f32 { ... }
impl LowerGen for f64 { ... }
impl<T: ?Sized + LowerGen, 'a> LowerGen for &'a T { ... }
impl<T: ?Sized + LowerGen, 'a> LowerGen for &'a mut T { ... }

impl UpperGen for f32 { ... }
impl UpperGen for f64 { ... }
impl<T: ?Sized + UpperGen, 'a> UpperGen for &'a T { ... }
impl<T: ?Sized + UpperGen, 'a> UpperGen for &'a mut T { ... }

```

The `format_args!` builtin macro is updated to support `:g` and `:G` as format specifiers, which map to these traits. They are usable in all of the same ways that `:e` and `:E` are.

## Some research necessary

This RFC may appear to be sparse on the precise details of the new format it proposes. This is because it will most likely benefit from a substantial review of the literature and implementations in other languages. There are lots of little knobs to turn, and strange and unusual edge cases that are difficult to anticipate.

For instance: Suppose it is decided that `format!("{:g}", 1e-4)` should output `"0.0001"` (a 5-character string), and now consider adding a width of `4`, so that it becomes `format!("{:4g}", 1e-4)`. Should this change the output, since `"1e-4"` fits into the width while `"0.0001"` does not? (The author would posit "no," as it is unclear how to generalize this edge case into something that feels natural)

## Specific formatting examples (tentative)

The following is a table of example outputs that showcase a number of the tunable knobs in the format. The columns for `{:g}` in these tables propose one possible set of decisions. **The decisions in this table are tentative and up to bikeshedding.** The choices made here were largely informed by reverse engineering the Python implementation, with some adjustments to fit better into rust's existing formatters.

Some of the knobs visible in this table are:

- Exponential-format thresholds for large and small values, both with and without a specified precision.
- Whether to append a trailing `.0` for integers or a leading `-` for `-0.0`.
- Whether to always print `p` significant figures when a precision `.p` is provided, or to omit trailing zeros.

**Without precision flags:**

| Value | `{}` | `{:?}` | `{:e}` | `{:g}` | Notes |
| --- | --- | --- | --- | --- | --- |
| `1.0` | `1` | `1.0` | `1e0` | **`1`** [^a] | No `.0` is consistent with `{}` |
| `0.0` | `1` | `0.0` | `0e0` | **`0`** [^a] | |
| `-0.0` | `0` | `-0.0` | `0e0` | **`0`** [^b] | No leading `-` is consistent with `{}` |
| `1.234` | `1.234` | `1.234` | `1.234e0` | **`1.234`** | |
| `100` | `100` | `100` | `1e2` | **`100`** [^a] | |
| `1000` | `1000` | `1000` | `1e3` | **`1000`** [^a] | Even though `1e3` is shorter |
| ... | ... | ... | ... | ... | |
| `1000000` | `1000000` | `1000000` | `1e6` | **`1000000`** [^a] | |
| `10000000` | `10000000` | `10000000` | `1e7` | **`1e7`** | Suggested default high cutoff |
| `0.0001` | `0.0001` | `0.0001` | `1e-4` | **`0.0001`** | |
| `0.00001` | `0.00001` | `0.00001` | `1e-5` | **`1e-5`** | Suggested default low cutoff |
| `(1.0f32 + EPSILON)` | `0.10000001` | `0.10000001` | `1.0000001e-1` | **`0.10000001`** | |
| `1e-7 * (1.0f32 + EPSILON)` | `0.000000100`  
`00001` | `0.000000100`  
`00001` | `1.0000001e-7` | **`1.0000001e-7`** | |

**With precision flags:**

| Value | Precision | `{:.p$}` | `{:.p$?}` | `{:.p$e}` | `{:.p$g}` | Notes |
| --- | --- | --- | --- | --- | --- | --- |
| `1.0` | `p=3` | `1.000` | `1.000` | `1.000e0` | **`1`** [^a] | Consistent with `{}` |
| `1.234` | `p=2` | `1.23` | `1.23` | `1.23e0` | **`1.23`** | |
| `1.234` | `p=3` | `1.234` | `1.234` | `1.234e0` | **`1.234`** | |
| `1.234` | `p=4` | `1.2340` | `1.2340` | `1.2340e0` | **`1.234`** | Truncates trailing zeros |
| `1e4` | `p=5` | `10000.00000` | `10000.00000` | `1.00000e4` | **`10000`** | |
| `1e4` | `p=4` | `10000.0000` | `10000.0000` | `1.0000e4` | **`1e4`** | Suggested high cutoff (support `p` digits before the decimal) |
| `1e-3` | `p=1` | `0.001` | `0.001` | `1e-1` | **`0.001`** | Low cutoff is always `1e-5` (what Python does) |
| `60000000` | `p=1` | `60000000.0` | `60000000.0` | `6.0e7` | **`6e7`** | Consistent with `{:e}` |
| `(1.0f32 + EPSILON)` | `p=10` | `1.0000001192` | `1.0000001192` | `1.0000001192e0` | **`1.0000001192`** | Excess digits faithfully represent the binary value |
| `1e-7 * (1.0f32 + EPSILON)` | `p=5` | `0.00000` | `0.00000` | `1.00000e-7` | **`1e-7`** | (as opposed to `0`) |

[^a]: If/when `{:g?}` becomes possible, it should add a trailing `.0` to these so that they are valid literals.

[^b]: If/when `{:g?}` becomes possible, it should render this as `-0.0`.

# Drawbacks

## Implementation difficulty

Efficient floating point formatting is not an easy problem. However, the author of this RFC has little expertise on the topic.

## Suggests a "batteries included" philosophy

Formatting floating point numbers nicely for humans requires making a number of decisions that don't have clear answers. Different domains may disagree, for instance, on what the best thresholds are for switching from standard notation to exponential notation, and no matter what choices are made, not everybody will be pleased.

This is partly why this RFC focuses great energy into the developer-oriented aspects, and declares future interaction with `Debug` as an explicit goal. Debug output _does not need to be perfect for everyone._ It seems unlikely that most people would even notice the difference between an upper threshold of `1e7` versus `1e16` (as anecdotal evidence, prior to writing this RFC, the author did not even realize that these two drastically different threshollds are used by Haskell and Python, respectively). Debug output largely just needs to maximize bang for the buck and please as many people as it can... and the status quo of `System { count: 602214085700000000000000 }` sets a pretty low bar for improvement!

## `{:g?}` may become preferred over `{:?}`

This is a disadvantage of the planned future RFC. There is tons of code that (a) already exists, (b) uses `{:?}`, and (c) ...probably would be better off using `{:g?}` instead. Such code will likely be fixed very slowly, and much of it won't ever be fixed at all.

This is a natural part of code evolution. Most alternatives share this drawback; the only way to overcome it would be with breaking changes to the standard library formatting impls.

It also raises the question: _should `{:gx?}` be supported?_

# Rationale and alternatives

## Alternative: Change the output of `{:?}`

A far more direct approach to the motivation; Introduce nothing new, and instead change the `{:?}` representation for `f32` and `f64` to work more like `{:g}` proposed here.

- **Pro: No new APIs.** No new traits, no changes to format specifiers.
- **Pro: Automatic adoption all over.** The benefits will be reaped in many more places, such as the `assert_eq!` macro.
- **Con: Massive breaking change!** Although _ideally_ there ought to be no code depending on `Debug` output representations, in reality this is far from the truth, and in practice there are even places that _should_ depend on it (e.g. `should_panic` patterns under certain conditions). About a year prior to the posting of this RFC, the `Debug` representation of floats was changed to include a trailing `.0` for integer values(FIXME link), and this did not go unnoticed. The changes listed here are of far greater magnitude.
- **Pro/Con: Potential for misuse?** People may use `{:?}` in human-oriented output because it "looks nicer."

## Alternative: Just add `{:e?}` and `{:E?}`.

Without introducing any implementation of general floating-point formatting, just add `{:e?}` specifiers. This would solve the issue presented in the `positive_normal_f32s` example. However, the author of this RFC would conjecture that the set of clear-cut good use cases for `{:e?}` is vanishingly small compared to `{:g?}`.

## Alternative: Make the formatting system extensible

(thanks to @crlf0710 for reminding me to add this)

This RFC proposes adding a new format, but as an alternative, we could make formatting extensible in a way that allows third party libraries to provide a new format. The big question is: ...._how,_ exactly?

While this does dodge some difficult questions and allow the standard library to remain general-purpose, it could be a massive design effort that will require a much greater and far more complicated RFC.

## Make this the alternative format `{:#?}` for floats

(thanks to @ekuber)

Like some other alternatives, this is a breaking change.

Unfortunately, this would force people to use `{:#?}` on structs as well. `{:#?}` is a very space-consuming representation that is far from ideal for most use-cases.

## Add another flag rather than a trait

([suggested](https://internals.rust-lang.org/t/pre-rfc-draft-g-or-floating-points-for-humans/9110/10) by @hanna-kruppe)

Basically, like the above idea, except introduce a new flag rather than repurposing `#`. This represents a large class of possible designs. However, the design closest to the current proposal would be:

- `{:g}` will call `Display::fmt` with a flag set on the `Formatter`, rather than using a new trait.
- `{:g?}` will call `Debug::fmt` with a flag set on the `Formatter`, as it would in the upcoming proposal.

The pros and cons of that specific design compared to this RFC are:

- **Pro: Unified API (in some ways).** `{:g}` and `{:g?}` will internally work similarly to each other, in contrast to `{:x}` and `{:x?}`.
- **Pro: Automatic support by newtype wrappers.** Any newtype wrappers that already implements all of the existing `std::fmt` traits by calling `{Trait}::fmt(&self.field, formatter)` will automatically gain support for `{:g}`. (note that automatic support for the debug counterpart `{:g?}` is already a goal of this RFC)
- **Con: Poorer type-checking.** When you write `format!("{:x}", 1.0)`, you get a type error. When you write `format!("{:g}", 1i32)`, you may get a runtime error, or more likely, no indication of any problem at all.  
Many types implement `Display` in a manner that performs a series of `write!()` invocations without any regard for formatting flags. These types will all end up accidentally "supporting" `{:g}` whether they were designed to support it or not.
- **Con: Poorly unified API (in other ways).** How do you support `{:e}`? Implement `LowerExp`. How do you support `{:g}`? Be careful in your `Display` impl.

There is also conceivably a design that adds `{:g?}` without ever adding `{:g}`. This removes the drawbacks listed above, but replaces them with other obvious drawbacks.

## Possible extension: Add `{:f}` and `std::fmt::Fixed` for fixed-point formatting

It is somewhat disappointing that floats use dedicated traits `{LowerExp,UpperExp}` for exponential formatting and the general-purpose trait `Display` for fixed-point formatting. Adding a new dedicated `Fixed` trait with a `:f` specifier would help create a more complete conceptual basis for talking about floating point formatting and may benefit newtypes that want to differentiate their `Fixed` and `Display` impls.

It is worth noting that `Debug` already recursively applies the precision in `{:.5?}`, meaning that this extension is _not necessary_ to backwards-compatibly add support for recursive fixed-point formatting (it's already there!).

At first glance, this alternative appears to even open a migration path to changing the meaning of `{}` or `{:?}` for floats, by deprecating these impls and generating a fixable migration warning to add missing `:f` specifiers to format literals. However, this is a false hope, as still nothing can detect or fix the usage of a function defined as `fn foo<T: fmt::Display>` or `fn foo<T: ToString>` called on a float.

# Prior art

TODO: Needs a lot more review

- Python's "default" formatter switches to exponential notation for any value `>= 1e16`. If you write `{:g}` without a precision, it instead behaves identical to `{:.6g}`.
- Haskell switches to exponential notation for any value `>= 1e7`.

# Unresolved questions

TODO

# Future possibilities

FIXME: some of the stuff mentioned in other parts actually belongs here

---

<div class="post-metadata">

**Author:** ![ekuber](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ekuber/32/1646_2.png) [@ekuber](https://internals.rust-lang.org/u/ekuber)\
**Post date:** [December 28, 2018, 1:44am UTC](https://internals.rust-lang.org/t/pre-rfc-draft-g-or-floating-points-for-humans/9110/2 "2018-12-28T01:44:49Z")

</div>

Another alternative would be to introduce this behavior behind the alternate debug output (`{:#?}`) for floats.

---

<div class="post-metadata">

**Author:** ![scottmcm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/scottmcm/32/2355_2.png) [@scottmcm](https://internals.rust-lang.org/u/scottmcm)\
**Post date:** [December 28, 2018, 4:08am UTC](https://internals.rust-lang.org/t/pre-rfc-draft-g-or-floating-points-for-humans/9110/3 "2018-12-28T04:08:19Z")

</div>

I definitely support having this available.

As a way to try it out, we’re allowed to change `Debug` implementations. We could try a “whichever is shorter” output that still round trips.

---

<div class="post-metadata">

**Author:** ![crlf0710](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/crlf0710/32/1987_2.png) [@crlf0710](https://internals.rust-lang.org/u/crlf0710)\
**Post date:** [December 28, 2018, 5:08am UTC](https://internals.rust-lang.org/t/pre-rfc-draft-g-or-floating-points-for-humans/9110/4 "2018-12-28T05:08:24Z")

</div>

Instead of creating another output format within std itself, actually i think it makes more sense to add an “extension mechanism” to format\_arguments etc, so this can actually be implemented in a lib?

---

<div class="post-metadata">

**Author:** ![tspiteri](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/tspiteri/32/7283_2.png) [@tspiteri](https://internals.rust-lang.org/u/tspiteri)\
**Post date:** [December 28, 2018, 9:53pm UTC](https://internals.rust-lang.org/t/pre-rfc-draft-g-or-floating-points-for-humans/9110/5 "2018-12-28T21:53:09Z")

</div>

Is there a need for an extension mechanism? You can already write a function

```rust
fn my_display<'a>(s: &'a Something) -> impl Display + 'a { /*...*/ }

```

and then

```rust
println!("{}", my_display(&something));

```

Or am I missing something?

---

<div class="post-metadata">

**Author:** ![ExpHP](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/exphp/32/6208_2.png) [@ExpHP](https://internals.rust-lang.org/u/ExpHP)\
**Post date:** [December 29, 2018, 5:06am UTC](https://internals.rust-lang.org/t/pre-rfc-draft-g-or-floating-points-for-humans/9110/7 "2018-12-29T05:06:57Z")

</div>

> [@crlf0710](#):
>
> Instead of creating another output format within std itself, actually i think it makes more sense to add an “extension mechanism” to format\_arguments etc, so this can actually be implemented in a lib?

Thanks, I initially intended to add that as an alternative, but I forgot.

> [@tspiteri](#):
>
> ```rust
> println!("{}", my_display(&something));
> 
> ```

That doesn't address the difficulty of formatting floats located in arbitrary places inside structs. This can only be addressed by either providing more builtin formatting methods, or by making the formatting system pluggable.

> [@scottmcm](#):
>
> “whichever is shorter”

One final note: The text in the RFC deliberately avoids using this language because I find it is not true of the implementations of `%g` that I enjoy using. It also seems more difficult to implement, with more surprising edge cases. This is why I focus on thresholds on absolute value.

---

<div class="post-metadata">

**Author:** ![tspiteri](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/tspiteri/32/7283_2.png) [@tspiteri](https://internals.rust-lang.org/u/tspiteri)\
**Post date:** [December 29, 2018, 10:09am UTC](https://internals.rust-lang.org/t/pre-rfc-draft-g-or-floating-points-for-humans/9110/8 "2018-12-29T10:09:27Z")

</div>

> [@ExpHP](#):
>
> That doesn’t address the difficulty of formatting floats located in arbitrary places inside structs. This can only be addressed by either providing more builtin formatting methods, or by making the formatting system pluggable.

Ah, yes. I don't like the idea of using formatting flags to format internal struct elements. For example I would prefer `struct S { mask: u32, /*...*/, count: u32 }` to display `mask` as `{:x}` and `count` as `{}`, and that kind of thing breaks down when you try to use a flag for complex structs instead of single elements. How internal fields are formatted should really be the responsibility of the struct's internal implementation; if anything the struct can provide a configurable display method like `fn display<'a>(&'a self, conf: Configuration) -> impl Display + 'a`.

But that is an aside on the alternative, not of your main recommendation. I actually agree that `{:g}` is missing from the current floating-point display formats.

---

<div class="post-metadata">

**Author:** ![ExpHP](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/exphp/32/6208_2.png) [@ExpHP](https://internals.rust-lang.org/u/ExpHP)\
**Post date:** [December 29, 2018, 5:34pm UTC](https://internals.rust-lang.org/t/pre-rfc-draft-g-or-floating-points-for-humans/9110/9 "2018-12-29T17:34:17Z")

</div>

I also wasn't too keen on `{:x?}`, but it does make sense for homogenous data structures like arrays, `Vec`, and most notably `&[u8]` (the type of `b`-string literals). The main trouble is that, in the general case as you look at increasingly-nested data structures, most of them are heterogenous.

In any case, given that `{:x?}` _does_ exist (as does recursive fixed-point formatting with `{:.4?}`), I'd like to capitalize on it. And in contrast to the existing debug-supported flags, `{:g?}` _is_ a fairly reliable choice for use with heterogenous structures!

* * *

> [@tspiteri](#):
>
> `fn display<'a>(&'a self, conf: Configuration) -> impl Display + 'a`

I might be picking nits here at your choice of the name `display` (since it seems to be drawing from the pattern used by `std::path::Path`), but I would argue that this does not scale for debugging. `Debug` and `Display` have very different requirements. `Display` should be used for user-facing output. I would implement `Display` for e.g. objects that represent file formats, command line arguments, or error messages. If you need to have a method to give a `Display` object, that's totally reasonable because it surely won't be dead code.

`#[derive(Debug)]` on the other hand, is implemented recursively for a reason. It should always be available with as little effort as possible, because the reasons for using it may appear and disappear on a whim. And a custom `debug() -> impl Display` method forces people to have to write manual `Debug` impls for structs containing that type.

I find it sad that e.g. python has a default impl for ` __str__ ` (our equivalent to `Display`) that calls ` __repr__ ` (our equivalent to `Debug`). Most people just conflate the two methods, and the end result is that we lose a very useful distinction in semantics.

---

<div class="post-metadata">

**Author:** ![hanna-kruppe](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/hanna-kruppe/32/6540_2.png) [@hanna-kruppe](https://internals.rust-lang.org/u/hanna-kruppe)\
**Post date:** [January 6, 2019, 3:52pm UTC](https://internals.rust-lang.org/t/pre-rfc-draft-g-or-floating-points-for-humans/9110/10 "2019-01-06T15:52:15Z")

</div>

> [@ExpHP](#):
>
> But currently, anything using `#[derive(Debug)]` has only one way to print its floats, which is poorly optimized for human readability. With a second future RFC to add support for `"{:g?}"` , users will be able to utilize the existing `Debug` machinery to easily inspect arbitrary data structures with floating point numbers of heterogenous magnitude:

This suggests to me this should be a _flag_ that goes into the formatting options (like `#`, precision, padding, etc.) rather than a new formatting trait. It doesn't have to be `#` precisely (that does have the disadvantage of affecting too many other things, in particular making struct debug formatting very verbose), but a trait seems questionable even without this extension (each new trait has ripple effects on APIs) and this extension is wholly incompatible with it.

---

<div class="post-metadata">

**Author:** ![ExpHP](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/exphp/32/6208_2.png) [@ExpHP](https://internals.rust-lang.org/u/ExpHP)\
**Post date:** [January 6, 2019, 9:35pm UTC](https://internals.rust-lang.org/t/pre-rfc-draft-g-or-floating-points-for-humans/9110/11 "2019-01-06T21:35:26Z")

</div>

This seems like a strange idea. `{:g}` and `{:g?}` feel like the natural extension of what we already have, which includes:

- `:e` and `:E` formatting. No doubt, these formatting modes (and all others except `Display` and `Debug`) would need to be incompatible with the new flag.
- recursive hexadecimal formatting (`{:2x?}`, `{:2X?}`)

> [@hanna-kruppe](#):
>
> (each new trait has ripple effects on APIs)

Can you please elaborate on this? To me it seems exceedingly rare for a type to implement traits like `std::fmt::{LowerExp,UpperExp}` or to depend on them in public APIs. I doubt any "ripple" effect observed should go much farther than, _user wants to use `{:g}` somewhere, but a single crate providing a newtype wrapper must be updated to implement the trait first._

> [@hanna-kruppe](#):
>
> and this extension is wholly incompatible with it.

Per what I said at the top of the post, I don't see what you mean here.

---

<div class="post-metadata">

**Author:** ![hanna-kruppe](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/hanna-kruppe/32/6540_2.png) [@hanna-kruppe](https://internals.rust-lang.org/u/hanna-kruppe)\
**Post date:** [January 14, 2019, 7:21pm UTC](https://internals.rust-lang.org/t/pre-rfc-draft-g-or-floating-points-for-humans/9110/12 "2019-01-14T19:21:29Z")

</div>

When I say a flag that goes into the formatting options, I am talking precisely about something like recursive hexadecimal formatting. Because that's how `{:x?}` is implemented: it calls `Debug` with a special flag set (`fmt::Formatter::debug_{lower,upper}_hex()`). While for hexadecimal integers there is a corresponding trait for historical reasons, this is [mentioned in the RFC](https://rust-lang.github.io/rfcs/2226-fmt-debug-hex.html#drawbacks) as a _drawback_ forced by backwards compatibility. For new kinds of formatting we could avoid that duplication.

> [@ExpHP](#):
>
> `:e` and `:E` formatting. No doubt, these formatting modes (and all others except `Display` and `Debug` ) would need to be incompatible with the new flag.

I don't see the issue, `x?` also doesn't work with other traits.

> [@ExpHP](#):
>
> Can you please elaborate on this? To me it seems exceedingly rare for a type to implement traits like `std::fmt::{LowerExp,UpperExp}` or to depend on them in public APIs. I doubt any “ripple” effect observed should go much farther than, _user wants to use `{:g}` somewhere, but a single crate providing a newtype wrapper must be updated to implement the trait first._

Well, all those newtype wrappers amount to quite a bit of code. There's also generic helper functions that want to accept "anything that can be `Debug`-formatted", if this is supposed to be the new good way to print floating point numbers for programmers, they'll have to consider whether they adopt the new format. (This is admittedly not specific to the trait, any new way to format has this issue.)

> [@ExpHP](#):
>
> Per what I said at the top of the post, I don’t see what you mean here.

Sorry, my mistake, it isn't incompatible, just redundant.

---

<div class="post-metadata">

**Author:** ![ExpHP](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/exphp/32/6208_2.png) [@ExpHP](https://internals.rust-lang.org/u/ExpHP)\
**Post date:** [January 16, 2019, 8:36pm UTC](https://internals.rust-lang.org/t/pre-rfc-draft-g-or-floating-points-for-humans/9110/13 "2019-01-16T20:36:49Z")

</div>

In response to this I elaborated in the RFC:

> ## Add another flag rather than a trait
> 
> Basically, like the above idea, except introduce a new flag rather than repurposing `#`. This represents a large class of possible designs. However, the design closest to the current proposal would be:
> 
> - `{:g}` will call `Display::fmt` with a flag set on the `Formatter`, rather than using a new trait.
> - `{:g?}` will call `Debug::fmt` with a flag set on the `Formatter`, as it would in the upcoming proposal.
> 
> The pros and cons of that specific design compared to this RFC are:
> 
> - **Pro: Unified API.** `{:g}` and `{:g?}` will internally work similarly to each other, in contrast to `{:x}` and `{:x?}`.
> - **Pro: Automatic support by newtype wrappers.** Any newtype wrappers that already implements all of the existing `std::fmt` traits by calling `{Trait}::fmt(&self.field, formatter)` will automatically gain support for `{:g}`. (note that automatic support for the debug counterpart `{:g?}` is already a goal of this RFC)
> - **Con: Poorer type-checking.** When you write `format!("{:x}", 1.0)`, you get a type error. When you write `format!("{:g}", 1i32)`, you may get a runtime error, or more likely, no indication of any problem at all.  
> Many types implement `Display` in a manner that performs a series of `write!()` invocations without any regard for formatting flags. These types will all end up accidentally "supporting" `{:g}` whether they were designed to support it or not.
> - **Con: Confusing compared to other format types.** How do you support `{:e}`? Implement `LowerExp`. How do you support `{:g}`? Be careful in your `Display` impl.
> 
> There is also conceivably a design that adds `{:g?}` without ever adding `{:g}`. This removes the drawbacks listed above, but replaces them with other obvious drawbacks.

---

<div class="post-metadata">

**Author:** ![system](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/system/32/14092_2.png) [@system](https://internals.rust-lang.org/u/system)\
**Post date:** [April 16, 2019, 8:36pm UTC](https://internals.rust-lang.org/t/pre-rfc-draft-g-or-floating-points-for-humans/9110/14 "2019-04-16T20:36:52Z")

</div>

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.

---

<div class="post-metadata">

**Author:** ![mbrubeck](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/mbrubeck/32/174_2.png) [@mbrubeck](https://internals.rust-lang.org/u/mbrubeck)\
**Post date:** [May 5, 2019, 4:03pm UTC](https://internals.rust-lang.org/t/pre-rfc-draft-g-or-floating-points-for-humans/9110/15 "2019-05-05T16:03:34Z")

</div>



---

<div class="post-metadata">

**Author:** ![vi0](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/vi0/32/750_2.png) [@vi0](https://internals.rust-lang.org/u/vi0)\
**Post date:** [May 7, 2019, 3:08am UTC](https://internals.rust-lang.org/t/pre-rfc-draft-g-or-floating-points-for-humans/9110/16 "2019-05-07T03:08:20Z")

</div>

Can something like this be implemented as a crate, outside std?

I look for, but haven’t found a library for this. Ended up rolling my own: [https://crates.io/crates/float-pretty-print](https://crates.io/crates/float-pretty-print).
