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

Fix inconsistent rounding of 0.5 when formatted to 0 decimal places #102935

Merged
merged 2 commits into from
Nov 16, 2022

Conversation

ajtribick
Copy link
Contributor

As described in #70336, when displaying values to zero decimal places the value of 0.5 is rounded to 1, which is inconsistent with the display of other half-integer values which round to even.

From testing the flt2dec implementation, it looks like this comes down to the condition in the fixed-width Dragon implementation where an empty buffer is treated as a case to apply rounding up. I believe the change below fixes it and updates only the relevant tests.

Nevertheless I am aware this is very much a core piece of functionality, so please take a very careful look to make sure I haven't missed anything. I hope this change does not break anything in the wider ecosystem as having a consistent rounding behaviour in floating point formatting is in my opinion a useful feature to have.

Resolves #70336

@rustbot rustbot added the T-libs Relevant to the library team, which will review and decide on the PR/issue. label Oct 11, 2022
@rust-highfive
Copy link
Collaborator

r? @m-ou-se

(rust-highfive has picked a reviewer for you, use r? to override)

@rustbot
Copy link
Collaborator

rustbot commented Oct 11, 2022

Hey! It looks like you've submitted a new PR for the library teams!

If this PR contains changes to any rust-lang/rust public library APIs then please comment with @rustbot label +T-libs-api -T-libs to tag it appropriately. If this PR contains changes to any unstable APIs please edit the PR description to add a link to the relevant API Change Proposal or create one if you haven't already. If you're unsure where your change falls no worries, just leave it as is and the reviewer will take a look and make a decision to forward on if necessary.

Examples of T-libs-api changes:

  • Stabilizing library features
  • Introducing insta-stable changes such as new implementations of existing stable traits on existing stable types
  • Introducing new or changing existing unstable library APIs (excluding permanently unstable features / features without a tracking issue)
  • Changing public documentation in ways that create new stability guarantees
  • Changing observable runtime behavior of library APIs

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Oct 11, 2022
@ajtribick
Copy link
Contributor Author

I've run a comparison for the formats {:.0} {:.1} and {:.9} for all positive finite f32 values, the only example affected was 0.5 in format {:.0}.

@ajtribick
Copy link
Contributor Author

@rustbot label +T-libs-api -T-libs

@rustbot rustbot added T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. and removed T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Oct 17, 2022
@scottmcm
Copy link
Member

scottmcm commented Oct 20, 2022

Quick demonstration that .0 is rounding odd while the other numbers of decimal places are rounding even:

[src/main.rs:2] format!("{:.0}", 0.5) = "1"
[src/main.rs:3] format!("{:.1}", 0.25) = "0.2"
[src/main.rs:4] format!("{:.1}", 0.75) = "0.8"
[src/main.rs:5] format!("{:.2}", 0.125) = "0.12"
[src/main.rs:6] format!("{:.2}", 0.875) = "0.88"
[src/main.rs:7] format!("{:.3}", 0.0625) = "0.062"

https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=a0ee562de13b361cc6a729d64e482ae8

@ajtribick
Copy link
Contributor Author

And just to show that it is specifically the behaviour of 0.5 that is the issue here:

[src/main.rs:2] format!("{:.0}", 0.5) = "1"
[src/main.rs:3] format!("{:.0}", 1.5) = "2"
[src/main.rs:4] format!("{:.0}", 2.5) = "2"
[src/main.rs:5] format!("{:.0}", 3.5) = "4"
[src/main.rs:6] format!("{:.0}", 4.5) = "4"
[src/main.rs:7] format!("{:.0}", 5.5) = "6"

https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=68c6c78969ae752c38e5ffcd769eabd4

@scottmcm
Copy link
Member

Oh! I hadn't realized it was just 0.5 with the problem. That pushes me to "this is just a bug", not really a decision to be made. (Still worth a relnotes mention, but might not even need an FCP.)

@rust-lang/libs-api would you be comfortable calling this a bug that can just be fixed, or do you need an FCP for it?
@rustbot label +I-libs-api-nominated

@rustbot rustbot added the I-libs-api-nominated The issue / PR has been nominated for discussion during a libs-api team meeting. label Oct 20, 2022
@inquisitivecrystal inquisitivecrystal added the relnotes Marks issues that should be documented in the release notes of the next release. label Oct 24, 2022
@blueglyph
Copy link

blueglyph commented Oct 25, 2022

Quick demonstration that .0 is rounding odd while the other numbers of decimal places are rounding even:

[src/main.rs:2] format!("{:.0}", 0.5) = "1"
[src/main.rs:3] format!("{:.1}", 0.25) = "0.2"
[src/main.rs:4] format!("{:.1}", 0.75) = "0.8"
[src/main.rs:5] format!("{:.2}", 0.125) = "0.12"
[src/main.rs:6] format!("{:.2}", 0.875) = "0.88"
[src/main.rs:7] format!("{:.3}", 0.0625) = "0.062"

https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=a0ee562de13b361cc6a729d64e482ae8

I'm sorry if I'm misunderstanding, I found a lot of other values, as shown in #70336 (for "to even" as well as "away from zero"). I was originally thinking it was supposed to round away from zero, but if fmt is supposed to round to even, I can adapt my test to hunt all the values down. Unless you're talking about the fix?

For example:

[src/main.rs:9] format!("{:.1}", 0.35) = "0.3"
[src/main.rs:10] format!("{:.2}", 0.155) = "0.15"
[src/main.rs:11] format!("{:.2}", 0.165) = "0.17"

EDIT: testing all the values at different depth (with a '5' at depth+1), I found about 50% of wrong rounding in the original fmt, no matter which mode (slightly fewer errors if we expect even but it's negligible). I haven't tested more complicated cases.

@scottmcm
Copy link
Member

scottmcm commented Oct 25, 2022

[src/main.rs:9] format!("{:.1}", 0.35) = "0.3"
[src/main.rs:10] format!("{:.2}", 0.155) = "0.15"
[src/main.rs:11] format!("{:.2}", 0.165) = "0.17"

Remember that anything that's not a multiple of an integer power of two doesn't really exist in floating-point numbers.

0.35_f64 is the most convenient way to write the floating point value that's exactly

0.34999999999999997779553950749686919152736663818359375​

And thus it rounds down https://float.exposed/0x3fd6666666666666

Similarly, 0.155 and 0.165 are

0.1549999999999999988897769753748434595763683319091796875​
0.1650000000000000077715611723760957829654216766357421875​

And thus they're not actually ties either.

It makes sense that you'd get about 50% of them rounding the other way, because for things that aren't representable exactly, you'd expect about 50% of them to be slightly too big and 50% of them to be slightly too small.

(I also made this mistake originally, but realized in time, and thus my examples above all use fractions where the denominator is a power of two -- ½, ¼, ¾, ⅛, ⅞, 1⁄16.)

Edit: Oh, hi @ajtribick, apparently we were racing on this one 😅

@blueglyph
Copy link

@scottmcm @ajtribick
You're right that they are not round values, but I thought it was precisely the problem solved by those algorithms. I'm not familiar enough with Grisu3/Dragon4 but if I take the decoded significand and base-10 exponent in the case of Dragonbox, I get those (u64, i32) values:

0.35  => sig=3500000000000000, exp=-16
0.155 => sig=1550000000000000, exp=-16
0.175 => sig=1750000000000000, exp=-16

I suppose the current algorithms operate differently. Yet it's strange that it fails on 50% of the ties, that's a lot.

@ajtribick
Copy link
Contributor Author

ajtribick commented Oct 25, 2022

@blueglyph - as I understand it, Dragonbox is an algorithm for producing the shortest roundtrippable representation of a floating point value (i.e. the operation corresponding to the {} format string: without a specified precision), not a floating point value rounded to a specified number of decimal places. This is a different operation and not necessarily the same as what you would get by operating on the decimal representation produced by the shortest representation algorithm.

FWIW charconv in MSVC behaves in the same way:

#include <array>
#include <charconv>
#include <iostream>
#include <string_view>
#include <system_error>

int main()
{
    std::array<double, 7> values = { 0.5, 0.25, 0.75, 0.125, 0.35, 0.155, 0.165 };
    std::array<char, 10> buffer{ 0 };

    for (double value : values)
    {
        if (auto [ptr, ec] = std::to_chars(buffer.data(), buffer.data() + buffer.size(), value, std::chars_format::fixed); ec == std::errc{})
        {
            std::cout << std::string_view(buffer.data(), ptr - buffer.data());
        }
        else
        {
            std::cout << "(FAIL)";
        }

        for (int precision = 0; precision < 3; ++precision)
        {
            if (auto [ptr, ec] = std::to_chars(buffer.data(), buffer.data() + buffer.size(), value, std::chars_format::fixed, precision); ec == std::errc{})
            {
                std::cout << '\t' << std::string_view(buffer.data(), ptr - buffer.data());
            }
            else
            {
                std::cout << "\t(FAIL)";
            }
        }
        std::cout << '\n';
    }
}

gives the following output (first column is shortest representation, followed by fixed precisions of 0, 1, 2 decimal places):

0.5     0       0.5     0.50
0.25    0       0.2     0.25
0.75    1       0.8     0.75
0.125   0       0.1     0.12
0.35    0       0.3     0.35
0.155   0       0.2     0.15
0.165   0       0.2     0.17

@scottmcm
Copy link
Member

scottmcm commented Oct 25, 2022

@blueglyph Note that floating-point algorithms are expected to treat the floating point number as if the represented value was exactly the desired value, and not to attempt to divine whether it came from rounding something else.

That's why, for example, it's absolutely correct that PI.sin() is not zero. PI is very close to π, but is not exactly π. So "turn it into a rounded string" also follows those rules, and even if there's a tie in the ±½ULP range around the exact floating point number, that doesn't mean it follows the tie rules. It's only a tie if the floating-point number itself is exactly on a tie.

@blueglyph
Copy link

@blueglyph - as I understand it, Dragonbox is an algorithm for producing the shortest roundtrippable representation of a floating point value (i.e. the operation corresponding to the {} format string: without a specified precision), not a floating point value rounded to a specified number of decimal places. This is a different operation and not necessarily the same as what you would get by operating on the decimal representation produced by the shortest representation algorithm.

Dragonbox is an algorithm to convert a binary floating-point value into a correctly rounded decimal representation. From there I don't see what you wouldn't be able to reduce the precision as you wish. But it is arguably another algorithm than the one used.

@blueglyph
Copy link

@blueglyph Note that floating-point algorithms are expected to treat the floating point number as if the represented value was exactly the desired value, and not to attempt to divine whether it came from rounding something else.

I would agree for operations on floating-points (*), but I'm not convinced it's true for their decimal representation, since we know the base 2 representation is not exactly the desired value, as we saw earlier.

(*) although they are rounded to even to prevent bias errors, so in a way we are already "attempting to divine" whether they should be pre-processed in the case of accumulation.

That's why, for example, it's absolutely correct that PI.sin() is not zero. PI is very close to π, but is not exactly π. So "turn it into a rounded string" also follows those rules, and even if there's a tie in the ±½ULP range around the exact floating point number, that doesn't mean it follows the tie rules. It's only a tie if the floating-point number itself is exactly on a tie.

PI is an irrational number, so the problem is different, and we're not applying the perfect sin function either but only an approximation. But I see what you mean by that.

@ajtribick
Copy link
Contributor Author

ajtribick commented Oct 25, 2022

Dragonbox is an algorithm to convert a binary floating-point value into a correctly rounded decimal representation. From there I don't see what you wouldn't be able to reduce the precision as you wish. But it is arguably another algorithm than the one used.

The output of Dragonbox is "correctly rounded" in the sense that it gives the shortest possible decimal representation of the value that can be parsed to give back the exact same input. It does not produce the exact representation of the numerical value of the variable. Note that rounding twice is not equivalent to rounding once, e.g. in decimal mathematics:

  • 1.47 rounded to 1 decimal place is 1.5, 1.5 rounded to 0 decimal places is 2.
  • 1.47 rounded to 0 decimal places is 1.

Reducing the precision of the Dragonbox output is likewise performing double rounding, and will lead to different results than rounding the value directly. The value of 0.35_f64 is less than 0.35 (once the program is compiled it cannot tell whether you wrote 0.35_f64 or 0.34999999999999997779553950749686919152736663818359375_f64 in the source code), and thus should be rounded down when rounding to 1 decimal place.

In any case, I fear this is going off on an irrelevant tangent to the change being done here: the value of 0.5 is exactly representable as both f32 and f64, and is being rounded inconsistently with every other situation where an exact tie occurs.

@scottmcm
Copy link
Member

but I'm not convinced it's true for their decimal representation, since we know the base 2 representation is not exactly the desired value, as we saw earlier.

I'm not sure what you mean by decimal representation here.

Do you agree that this is correct?

format!("{:.1}", 3152519739159347.0 / 9007199254740992.0) => "0.3"

https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=57517cb288ef19ff42707ea1e866e4dc

@blueglyph
Copy link

blueglyph commented Oct 26, 2022

I'm sorry this is going out of the initial topic, but this claims to solve #70336 and my argument is about that part. If more appropriate, it could be discussed elsewhere.

Grisu, like Dragonbox, aim to convert a binary-coded floating points to a decimal representation which is correct (in the sense mentioned earlier, the parsed decimal representation yields the same binary coding). Here the coding is typically IEEE-754, with a current focus on double precision.

The above conclusion "thus should be rounded down when rounding to 1 decimal place" seems strange to me, because there is no way to assert that.

For example, 0.35 is coded like this:

6305039478318694*2^-54 or 0x16666666666666*2^0xffca => 0.34999999999999997779553950749686919152736663818359375

The value has been rounded to the 54-bit normalized mantissa using the round-even method, and indeed it's not a tie anymore (in decimal representation). If I increase the mantissa, I get this value:

6305039478318695*2^-54 or 0x16666666666667*2^0xffca => 0.350000000000000033306690738754696212708950042724609375

which is on the other side of the tie. So we see here that the error introduced when parsing "0.35" and initially rounding the value to code it as an f64 doesn't allow us to deduce on which side of the tie the initial value was.

Thus the operation that Dragonbox (or Grisu, Ryu, etc) does to minimize the output length while preserving the information and keeping a "correct" output, is not wrong. And it looks like it's more likely to be what the initial value was when it matters:

  • if the initial value was 0.35, that is what we get
  • if the initial value was 0.349999999999999978, likely as a result of a calculation, does it matter if the displayed value is "0.35"? No, because the error margin is the same. Likewise for rounding as "0.4" with {:.1} by assuming it was a tie.

At least that's how I understand the asymmetric problem of coding and displaying floating-point values respectively in base 2 and 10.

If we come back to the initial problem to solve, the current solution seems to be wrong in about 50% of the cases, which is a lot. So I'm only wondering whether there could be another problem than just the case of 0.5, but maybe in the scope of another code change.

I'll stop here, however, and sorry again if that was not the place.

I'm not sure what you mean by decimal representation here.

Do you agree that this is correct?

format!("{:.1}", 3152519739159347.0 / 9007199254740992.0) => "0.3"

I mean by that the decimal interpretation of the value which is coded in binary (IEEE-754). How the value is printed, if you will. Hopefully the first part of my post already clarified that. :)

I don't see the point of the last question.

@ajtribick
Copy link
Contributor Author

ajtribick commented Oct 26, 2022

I'm sorry this is going out of the initial topic, but this claims to solve #70336 and my argument is about that part. If more appropriate, it could be discussed elsewhere.

I claim this issue solves #70336 because it addresses the issue as described in the very first post there: the rounding of half-integer values follows round-ties-to-even rules except for the case of 0.5.

If you need to have 0.35 behave as exactly halfway between 0.3 and 0.4, finite-length binary floating point types like f32 and f64 are not appropriate since they cannot represent these values, you should use a decimal floating point type instead.

@m-ou-se m-ou-se removed the I-libs-api-nominated The issue / PR has been nominated for discussion during a libs-api team meeting. label Nov 15, 2022
@bors
Copy link
Contributor

bors commented Nov 15, 2022

📌 Commit aa9837b has been approved by scottmcm

It is now in the queue for this repository.

@rustbot rustbot assigned scottmcm and unassigned m-ou-se Nov 15, 2022
@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Nov 15, 2022
@Manishearth
Copy link
Member

If you might want it as a bisection point it probably ought to be rollup=never, i was about to include it in a rollup 😄

@bors rollup=never

@bors
Copy link
Contributor

bors commented Nov 15, 2022

⌛ Testing commit aa9837b with merge 9486a40a00853a33b000cd654ce485d6acc4c753...

@bors
Copy link
Contributor

bors commented Nov 15, 2022

💔 Test failed - checks-actions

@bors bors added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. labels Nov 15, 2022
@rust-log-analyzer
Copy link
Collaborator

A job failed! Check out the build log: (web) (plain)

Click to see the possible cause of the failure (guessed by this bot)

@scottmcm
Copy link
Member

I couldn't find any actual failures here, and apparently neither could @rust-log-analyzer, so
@bors retry

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Nov 16, 2022
@bors
Copy link
Contributor

bors commented Nov 16, 2022

⌛ Testing commit aa9837b with merge e702534...

@bors
Copy link
Contributor

bors commented Nov 16, 2022

☀️ Test successful - checks-actions
Approved by: scottmcm
Pushing e702534 to master...

@bors bors added the merged-by-bors This PR was explicitly merged by bors. label Nov 16, 2022
@bors bors merged commit e702534 into rust-lang:master Nov 16, 2022
@rustbot rustbot added this to the 1.67.0 milestone Nov 16, 2022
@rust-timer
Copy link
Collaborator

Finished benchmarking commit (e702534): comparison URL.

Overall result: ❌ regressions - no action needed

@rustbot label: -perf-regression

Instruction count

This is a highly reliable metric that was used to determine the overall result at the top of this comment.

mean range count
Regressions ❌
(primary)
- - 0
Regressions ❌
(secondary)
1.4% [1.3%, 1.4%] 2
Improvements ✅
(primary)
- - 0
Improvements ✅
(secondary)
- - 0
All ❌✅ (primary) - - 0

Max RSS (memory usage)

Results

This is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.

mean range count
Regressions ❌
(primary)
- - 0
Regressions ❌
(secondary)
4.6% [1.6%, 8.3%] 3
Improvements ✅
(primary)
- - 0
Improvements ✅
(secondary)
-0.9% [-0.9%, -0.9%] 2
All ❌✅ (primary) - - 0

Cycles

This benchmark run did not return any relevant results for this metric.

@ajtribick ajtribick deleted the display-float-0.5-fixed-0 branch November 16, 2022 16:43
bors bot added a commit to Nullus157/stylish-rs that referenced this pull request Nov 17, 2022
28: Avoid change in float rounding behaviour in tests r=Nemo157 a=Nemo157

rust-lang/rust#102935 changed the behaviour of `format!("{:.0}", 0.5)` to round to 0 instead of 1 for consistency. The test case I copied from `std` was using this, so change to using 1.5 which has the same behaviour on stable and nightly.

Co-authored-by: Wim Looman <git@nemo157.com>
Aaron1011 pushed a commit to Aaron1011/rust that referenced this pull request Jan 6, 2023
… r=scottmcm

Fix inconsistent rounding of 0.5 when formatted to 0 decimal places

As described in rust-lang#70336, when displaying values to zero decimal places the value of 0.5 is rounded to 1, which is inconsistent with the display of other half-integer values which round to even.

From testing the flt2dec implementation, it looks like this comes down to the condition in the fixed-width Dragon implementation where an empty buffer is treated as a case to apply rounding up. I believe the change below fixes it and updates only the relevant tests.

Nevertheless I am aware this is very much a core piece of functionality, so please take a very careful look to make sure I haven't missed anything. I hope this change does not break anything in the wider ecosystem as having a consistent rounding behaviour in floating point formatting is in my opinion a useful feature to have.

Resolves rust-lang#70336
wip-sync pushed a commit to NetBSD/pkgsrc-wip that referenced this pull request Jan 27, 2023
Pkgsrc changes:
 * Adjust patches and cargo checksums to new versions,
   but also one strange "mips" conditional.

Upstream changes:

Version 1.67.0 (2023-01-26)
==========================

Language
--------

- [Make `Sized` predicates coinductive, allowing cycles.]
  (rust-lang/rust#100386)
- [`#[must_use]` annotations on `async fn` also affect the
  `Future::Output`.] (rust-lang/rust#100633)
- [Elaborate supertrait obligations when deducing closure signatures.]
  (rust-lang/rust#101834)
- [Invalid literals are no longer an error under `cfg(FALSE)`.]
  (rust-lang/rust#102944)
- [Unreserve braced enum variants in value namespace.]
  (rust-lang/rust#103578)

Compiler
--------

- [Enable varargs support for calling conventions other than `C`
  or `cdecl`.] (rust-lang/rust#97971)
- [Add new MIR constant propagation based on dataflow analysis.]
  (rust-lang/rust#101168)
- [Optimize field ordering by grouping m\*2^n-sized fields with
  equivalently aligned ones.] (rust-lang/rust#102750)
- [Stabilize native library modifier `verbatim`.]
  (rust-lang/rust#104360)

Added and removed targets:

- [Add a tier 3 target for PowerPC on AIX]
  (rust-lang/rust#102293), `powerpc64-ibm-aix`.
- [Add a tier 3 target for the Sony PlayStation 1]
  (rust-lang/rust#102689), `mipsel-sony-psx`.
- [Add tier 3 `no_std` targets for the QNX Neutrino RTOS]
  (rust-lang/rust#102701),
  `aarch64-unknown-nto-qnx710` and `x86_64-pc-nto-qnx710`.
- [Remove tier 3 `linuxkernel` targets]
  (rust-lang/rust#104015) (not used by the
  actual kernel).

Refer to Rust's [platform support page][platform-support-doc]
for more information on Rust's tiered platform support.

Libraries
---------

- [Merge `crossbeam-channel` into `std::sync::mpsc`.]
  (rust-lang/rust#93563)
- [Fix inconsistent rounding of 0.5 when formatted to 0 decimal places.]
  (rust-lang/rust#102935)
- [Derive `Eq` and `Hash` for `ControlFlow`.]
  (rust-lang/rust#103084)
- [Don't build `compiler_builtins` with `-C panic=abort`.]
  (rust-lang/rust#103786)

Stabilized APIs
---------------

- [`{integer}::checked_ilog`]
  (https://doc.rust-lang.org/stable/std/primitive.i32.html#method.checked_ilog)
- [`{integer}::checked_ilog2`]
  (https://doc.rust-lang.org/stable/std/primitive.i32.html#method.checked_ilog2)
- [`{integer}::checked_ilog10`]
  (https://doc.rust-lang.org/stable/std/primitive.i32.html#method.checked_ilog10)
- [`{integer}::ilog`]
  (https://doc.rust-lang.org/stable/std/primitive.i32.html#method.ilog)
- [`{integer}::ilog2`]
  (https://doc.rust-lang.org/stable/std/primitive.i32.html#method.ilog2)
- [`{integer}::ilog10`]
  (https://doc.rust-lang.org/stable/std/primitive.i32.html#method.ilog10)
- [`NonZeroU*::ilog2`]
  (https://doc.rust-lang.org/stable/std/num/struct.NonZeroU32.html#method.ilog2)
- [`NonZeroU*::ilog10`]
  (https://doc.rust-lang.org/stable/std/num/struct.NonZeroU32.html#method.ilog10)
- [`NonZero*::BITS`]
  (https://doc.rust-lang.org/stable/std/num/struct.NonZeroU32.html#associatedconstant.BITS)

These APIs are now stable in const contexts:

- [`char::from_u32`]
  (https://doc.rust-lang.org/stable/std/primitive.char.html#method.from_u32)
- [`char::from_digit`]
  (https://doc.rust-lang.org/stable/std/primitive.char.html#method.from_digit)
- [`char::to_digit`]
  (https://doc.rust-lang.org/stable/std/primitive.char.html#method.to_digit)
- [`core::char::from_u32`]
  (https://doc.rust-lang.org/stable/core/char/fn.from_u32.html)
- [`core::char::from_digit`]
  (https://doc.rust-lang.org/stable/core/char/fn.from_digit.html)

Compatibility Notes
-------------------

- [The layout of `repr(Rust)` types now groups m\*2^n-sized fields
  with equivalently aligned ones.]
  (rust-lang/rust#102750) This is intended
  to be an optimization, but it is also known to increase type
  sizes in a few cases for the placement of enum tags. As a reminder,
  the layout of `repr(Rust)` types is an implementation detail,
  subject to change.
- [0.5 now rounds to 0 when formatted to 0 decimal places.]
  (rust-lang/rust#102935)
  This makes it consistent with the rest of floating point formatting that
  rounds ties toward even digits.
- [Chains of `&&` and `||` will now drop temporaries from their
  sub-expressions in evaluation order, left-to-right.]
  (rust-lang/rust#103293) Previously, it
  was "twisted" such that the _first_ expression dropped its
  temporaries _last_, after all of the other expressions dropped
  in order.
- [Underscore suffixes on string literals are now a hard error.]
  (rust-lang/rust#103914)
  This has been a future-compatibility warning since 1.20.0.
- [Stop passing `-export-dynamic` to `wasm-ld`.]
  (rust-lang/rust#105405)
- [`main` is now mangled as `__main_void` on `wasm32-wasi`.]
  (rust-lang/rust#105468)
- [Cargo now emits an error if there are multiple registries in
  the configuration with the same index URL.]
  (rust-lang/cargo#10592)

Internal Changes
----------------

These changes do not affect any public interfaces of Rust, but they
represent significant improvements to the performance or internals
of rustc and related tools.

- [Rewrite LLVM's archive writer in Rust.]
  (rust-lang/rust#97485)
netbsd-srcmastr pushed a commit to NetBSD/pkgsrc that referenced this pull request Apr 8, 2023
Pkgsrc changes:
 * Adjust patches (add & remove) and cargo checksums to new versions.
 * It's conceivable that the workaround for LLVM based NetBSD works
   even less in this version (ref. PKGSRC_HAVE_LIBCPP not having a
   corresponding patch anymore).

Upstream changes:

Version 1.68.2 (2023-03-28)
===========================

- [Update the GitHub RSA host key bundled within Cargo]
  (rust-lang/cargo#11883).
  The key was [rotated by GitHub]
  (https://github.blog/2023-03-23-we-updated-our-rsa-ssh-host-key/)
  on 2023-03-24 after the old one leaked.
- [Mark the old GitHub RSA host key as revoked]
  (rust-lang/cargo#11889).
  This will prevent Cargo from accepting the leaked key even when
  trusted by the system.
- [Add support for `@revoked` and a better error message for
  `@cert-authority` in Cargo's SSH host key verification]
  (rust-lang/cargo#11635)

Version 1.68.1 (2023-03-23)
===========================

- [Fix miscompilation in produced Windows MSVC artifacts]
  (rust-lang/rust#109094)
  This was introduced by enabling ThinLTO for the distributed rustc
  which led to miscompilations in the resulting binary. Currently
  this is believed to be limited to the -Zdylib-lto flag used for
  rustc compilation, rather than a general bug in ThinLTO, so only
  rustc artifacts should be affected.
- [Fix --enable-local-rust builds]
  (rust-lang/rust#109111)
- [Treat `$prefix-clang` as `clang` in linker detection code]
  (rust-lang/rust#109156)
- [Fix panic in compiler code]
  (rust-lang/rust#108162)

Version 1.68.0 (2023-03-09)
===========================

Language
--------

- [Stabilize default_alloc_error_handler]
  (rust-lang/rust#102318)
  This allows usage of `alloc` on stable without requiring the
  definition of a handler for allocation failure. Defining custom
  handlers is still unstable.
- [Stabilize `efiapi` calling convention.]
  (rust-lang/rust#105795)
- [Remove implicit promotion for types with drop glue]
  (rust-lang/rust#105085)

Compiler
--------

- [Change `bindings_with_variant_name` to deny-by-default]
  (rust-lang/rust#104154)
- [Allow .. to be parsed as let initializer]
  (rust-lang/rust#105701)
- [Add `armv7-sony-vita-newlibeabihf` as a tier 3 target]
  (rust-lang/rust#105712)
- [Always check alignment during compile-time const evaluation]
  (rust-lang/rust#104616)
- [Disable "split dwarf inlining" by default.]
  (rust-lang/rust#106709)
- [Add vendor to Fuchsia's target triple]
  (rust-lang/rust#106429)
- [Enable sanitizers for s390x-linux]
  (rust-lang/rust#107127)

Libraries
---------

- [Loosen the bound on the Debug implementation of Weak.]
  (rust-lang/rust#90291)
- [Make `std::task::Context` !Send and !Sync]
  (rust-lang/rust#95985)
- [PhantomData layout guarantees]
  (rust-lang/rust#104081)
- [Don't derive Debug for `OnceWith` & `RepeatWith`]
  (rust-lang/rust#104163)
- [Implement DerefMut for PathBuf]
  (rust-lang/rust#105018)
- [Add O(1) `Vec -> VecDeque` conversion guarantee]
  (rust-lang/rust#105128)
- [Leak amplification for peek_mut() to ensure BinaryHeap's invariant
  is always met]
  (rust-lang/rust#105851)

Stabilized APIs
---------------

- [`{core,std}::pin::pin!`]
  (https://doc.rust-lang.org/stable/std/pin/macro.pin.html)
- [`impl From<bool> for {f32,f64}`]
  (https://doc.rust-lang.org/stable/std/primitive.f32.html#impl-From%3Cbool%3E-for-f32)
- [`std::path::MAIN_SEPARATOR_STR`]
  (https://doc.rust-lang.org/stable/std/path/constant.MAIN_SEPARATOR_STR.html)
- [`impl DerefMut for PathBuf`]
  (https://doc.rust-lang.org/stable/std/path/struct.PathBuf.html#impl-DerefMut-for-PathBuf)

These APIs are now stable in const contexts:

- [`VecDeque::new`]
  (https://doc.rust-lang.org/stable/std/collections/struct.VecDeque.html#method.new)

Cargo
-----

- [Stabilize sparse registry support for crates.io]
  (rust-lang/cargo#11224)
- [`cargo build --verbose` tells you more about why it recompiles.]
  (rust-lang/cargo#11407)
- [Show progress of crates.io index update even `net.git-fetch-with-cli`
  option enabled]
  (rust-lang/cargo#11579)

Misc
----

Compatibility Notes
-------------------

- [Add `SEMICOLON_IN_EXPRESSIONS_FROM_MACROS` to future-incompat report]
  (rust-lang/rust#103418)
- [Only specify `--target` by default for `-Zgcc-ld=lld` on wasm]
  (rust-lang/rust#101792)
- [Bump `IMPLIED_BOUNDS_ENTAILMENT` to Deny + ReportNow]
  (rust-lang/rust#106465)
- [`std::task::Context` no longer implements Send and Sync]
  (rust-lang/rust#95985)

nternal Changes
----------------

These changes do not affect any public interfaces of Rust, but they represent
significant improvements to the performance or internals of rustc and related
tools.

- [Encode spans relative to the enclosing item]
  (rust-lang/rust#84762)
- [Don't normalize in AstConv]
  (rust-lang/rust#101947)
- [Find the right lower bound region in the scenario of partial order relations]
  (rust-lang/rust#104765)
- [Fix impl block in const expr]
  (rust-lang/rust#104889)
- [Check ADT fields for copy implementations considering regions]
  (rust-lang/rust#105102)
- [rustdoc: simplify JS search routine by not messing with lev distance]
  (rust-lang/rust#105796)
- [Enable ThinLTO for rustc on `x86_64-pc-windows-msvc`]
  (rust-lang/rust#103591)
- [Enable ThinLTO for rustc on `x86_64-apple-darwin`]
  (rust-lang/rust#103647)

Version 1.67.0 (2023-01-26)
==========================

Language
--------

- [Make `Sized` predicates coinductive, allowing cycles.]
  (rust-lang/rust#100386)
- [`#[must_use]` annotations on `async fn` also affect the
  `Future::Output`.] (rust-lang/rust#100633)
- [Elaborate supertrait obligations when deducing closure signatures.]
  (rust-lang/rust#101834)
- [Invalid literals are no longer an error under `cfg(FALSE)`.]
  (rust-lang/rust#102944)
- [Unreserve braced enum variants in value namespace.]
  (rust-lang/rust#103578)

Compiler
--------

- [Enable varargs support for calling conventions other than `C`
  or `cdecl`.] (rust-lang/rust#97971)
- [Add new MIR constant propagation based on dataflow analysis.]
  (rust-lang/rust#101168)
- [Optimize field ordering by grouping m\*2^n-sized fields with
  equivalently aligned ones.] (rust-lang/rust#102750)
- [Stabilize native library modifier `verbatim`.]
  (rust-lang/rust#104360)

Added and removed targets:

- [Add a tier 3 target for PowerPC on AIX]
  (rust-lang/rust#102293), `powerpc64-ibm-aix`.
- [Add a tier 3 target for the Sony PlayStation 1]
  (rust-lang/rust#102689), `mipsel-sony-psx`.
- [Add tier 3 `no_std` targets for the QNX Neutrino RTOS]
  (rust-lang/rust#102701),
  `aarch64-unknown-nto-qnx710` and `x86_64-pc-nto-qnx710`.
- [Remove tier 3 `linuxkernel` targets]
  (rust-lang/rust#104015) (not used by the
  actual kernel).

Refer to Rust's [platform support page][platform-support-doc]
for more information on Rust's tiered platform support.

Libraries
---------

- [Merge `crossbeam-channel` into `std::sync::mpsc`.]
  (rust-lang/rust#93563)
- [Fix inconsistent rounding of 0.5 when formatted to 0 decimal places.]
  (rust-lang/rust#102935)
- [Derive `Eq` and `Hash` for `ControlFlow`.]
  (rust-lang/rust#103084)
- [Don't build `compiler_builtins` with `-C panic=abort`.]
  (rust-lang/rust#103786)

Stabilized APIs
---------------

- [`{integer}::checked_ilog`]
  (https://doc.rust-lang.org/stable/std/primitive.i32.html#method.checked_ilog)
- [`{integer}::checked_ilog2`]
  (https://doc.rust-lang.org/stable/std/primitive.i32.html#method.checked_ilog2)
- [`{integer}::checked_ilog10`]
  (https://doc.rust-lang.org/stable/std/primitive.i32.html#method.checked_ilog10)
- [`{integer}::ilog`]
  (https://doc.rust-lang.org/stable/std/primitive.i32.html#method.ilog)
- [`{integer}::ilog2`]
  (https://doc.rust-lang.org/stable/std/primitive.i32.html#method.ilog2)
- [`{integer}::ilog10`]
  (https://doc.rust-lang.org/stable/std/primitive.i32.html#method.ilog10)
- [`NonZeroU*::ilog2`]
  (https://doc.rust-lang.org/stable/std/num/struct.NonZeroU32.html#method.ilog2)
- [`NonZeroU*::ilog10`]
  (https://doc.rust-lang.org/stable/std/num/struct.NonZeroU32.html#method.ilog10)
- [`NonZero*::BITS`]
  (https://doc.rust-lang.org/stable/std/num/struct.NonZeroU32.html#associatedconstant.BITS)

These APIs are now stable in const contexts:

- [`char::from_u32`]
  (https://doc.rust-lang.org/stable/std/primitive.char.html#method.from_u32)
- [`char::from_digit`]
  (https://doc.rust-lang.org/stable/std/primitive.char.html#method.from_digit)
- [`char::to_digit`]
  (https://doc.rust-lang.org/stable/std/primitive.char.html#method.to_digit)
- [`core::char::from_u32`]
  (https://doc.rust-lang.org/stable/core/char/fn.from_u32.html)
- [`core::char::from_digit`]
  (https://doc.rust-lang.org/stable/core/char/fn.from_digit.html)

Compatibility Notes
-------------------

- [The layout of `repr(Rust)` types now groups m\*2^n-sized fields
  with equivalently aligned ones.]
  (rust-lang/rust#102750) This is intended
  to be an optimization, but it is also known to increase type
  sizes in a few cases for the placement of enum tags. As a reminder,
  the layout of `repr(Rust)` types is an implementation detail,
  subject to change.
- [0.5 now rounds to 0 when formatted to 0 decimal places.]
  (rust-lang/rust#102935)
  This makes it consistent with the rest of floating point formatting that
  rounds ties toward even digits.
- [Chains of `&&` and `||` will now drop temporaries from their
  sub-expressions in evaluation order, left-to-right.]
  (rust-lang/rust#103293) Previously, it
  was "twisted" such that the _first_ expression dropped its
  temporaries _last_, after all of the other expressions dropped
  in order.
- [Underscore suffixes on string literals are now a hard error.]
  (rust-lang/rust#103914)
  This has been a future-compatibility warning since 1.20.0.
- [Stop passing `-export-dynamic` to `wasm-ld`.]
  (rust-lang/rust#105405)
- [`main` is now mangled as `__main_void` on `wasm32-wasi`.]
  (rust-lang/rust#105468)
- [Cargo now emits an error if there are multiple registries in
  the configuration with the same index URL.]
  (rust-lang/cargo#10592)

Internal Changes
----------------

These changes do not affect any public interfaces of Rust, but they
represent significant improvements to the performance or internals
of rustc and related tools.

- [Rewrite LLVM's archive writer in Rust.]
  (rust-lang/rust#97485)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
merged-by-bors This PR was explicitly merged by bors. relnotes Marks issues that should be documented in the release notes of the next release. S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Float Display with fixed precision output uses inconsistent rounding rules