How to avoid "-0" as double.ToString() result after porting from .NET Framework 4.7.2 to .NET5.0?

Viewed 369

I am porting a .NET Framework 4.7.2 Visual Studio project to .NET5.0 and I am experiencing a different behaviour of double.ToString when the value is negative and close to zero.

For example, the double value -7.1054273576010019E-15 when converted to string returns "-0" even if I round it before the conversion while with the .NET Framework 4.7.2 its result was "0" (same code).

This difference is discussed here https://devblogs.microsoft.com/dotnet/floating-point-parsing-and-formatting-improvements-in-net-core-3-0/ but I don't really agree that this is an improvement as the title states, I believe 0 should not have a sign, it is neither a positive number nor a negative number.

I know I can create a custom IFormatProvider or an extension method and convert the double as I want but this requires a change in every conversion in the code and also any developers working on the project will need to use it in the future. In my opionion this solution is not very intuitive and it's likely to be source of errors.

Is there a way to restore the previous behaviour with less effort? Is Microsoft willing to change this in the future versions of the .NET?

EDIT: I asked the same thing in a discussion here https://github.com/dotnet/runtime/discussions/54537 If it could be helpful to someone else.

2 Answers

From the linked post, it sounds like the change was made in order to be more compliant with IEEE 754, which is the behavior all languages try to be compliant with to minimize confusion - or at least standardize a particular form of confusion.

It's always possible that they will revert such changes if it becomes too backwards-incompatible and breaks people's programs en masse, but if it hasn't been done by this point (it's already in .NET Core 3.1, which is an LTS release, and in .NET 5) I don't think it will be. But asking here whether "Microsoft is willing to change this" is the wrong place - file an issue in dotnet/runtime and ask Microsoft directly.

The workaround needs to go everywhere but is also simple: replace "-0" with "0".

Math.Abs will map both negative zero (which you may get from rounding, or in other ways) and positive zero into positive zero.

So instead of replacing "-0" with "0" as strings, you could use Abs.

But maybe you can also just do:

if (rounded == 0.0) {
    rounded = 0.0;  // POSITIVE zero
}

That should map both types of zero into the positive zero.

Inside an expression, that might be written as rounded == 0.0 ? 0.0 : rounded.

It is clear how you could write an extension method to double which will unite the two types of zeros (and leave all other double values unchanged).

Related questions here:

-0.1.ToString("0") is "-0" in .NET Core and "0" in .NET Framework

which is marked as a duplicate of:

.net core 3 yields different floating point results from version 2.2

Related