Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is infinity printed as "8" in the Windows 10 console?

Tags:

c#

.net

windows

Be assured that the floating point value is +Infinity if the numerator of a floating point division by zero is positive, -Infinity if the numerator of a floating point division by zero is negative, and NaN if the numerator and denominator of a floating point division are both zero. That's in the IEEE754 floating point specification, which is what C# uses.

In your case, the console is converting the infinity symbol (which is sometimes represented typographically as a horizontal 8 — ∞) to a vertical 8.


Given certain settings (i.e. combination of cultures, output encoding, etc.) .NET will output the Unicode infinity character ∞ (∞ / ∞). The Windows 10 console/terminal emulator will (again given certain settings - see screenshot below) display this Unicode character as an 8.

For example, on Windows 10, with the below settings (note the code page) simply pasting ∞ into the console shows as 8.

Setting to reproduce

EDIT

With thanks to comment from Chris: It seems that the output font in combination with the code page is responsible for the ∞ => 8 issue on the console. Like him I get proper display of ∞ in all the TrueType fonts I have tried and only see 8 when raster fonts' is chosen.

font settings


The 8 symbol occurs when Windows converts Unicode to a legacy character encoding. Since there is no infinity symbol in the legacy encoding, it uses a "best fit" to that symbol, by default, which in this case is the number 8. See an example for Microsoft's "windows-1252" encoding. Apparently, Windows 10 still uses legacy character encodings by default in the console (see "Code Pages").


Note: The implicit .ToString() method call when writing Double.PositiveInfinity to console is responsible for this behavior.

Calling Console.WriteLine(Double.PositiveInfinity.ToString(new CultureInfo("en-Us")));

results in the string "Infinity"

while Console.WriteLine(Double.PositiveInfinity.ToString(new CultureInfo("fr-Fr"))); results in "+Infini".

Edit: As others have pointed out in the commets, they cannot entirely confirm my results. Testing this on a different machine, I get the character for both calls.

Output for all cultures, thanks to vtortola in the comments.


I found a (likely) answer:

Using Console.OutputEncoding = Encoding.Unicode; I can recreate the behavior you are experiencing for several cultures, e.g. "ru", "ru-RU" produce the output 8.


Repro code:

using System;
using System.Text;

class Program {
    static void Main(string[] args) {
        var infinity = "\u221e";
        Console.OutputEncoding = Encoding.GetEncoding(1252);
        Console.WriteLine(infinity);
        Console.ReadLine();
    }
}

Code page 1252 is a pretty common accident in England since it is the default Windows code page there. As it is for Western Europe and the Americas. Lots of reasons to change the default Console.OutputEncoding property programmatically, many text files will be encoded in 1252. Or from the command line by typing chcp 1252 (chcp == change code page) before starting the program.

As you can tell from the character set supported by 1252, the Infinity symbol is not available. So the Encoding has to come up with a substitute. That is often the ? glyph for unsupported Unicode codepoints, the Encoding.EncoderFallback property value for 8-bit encodings. But for 1252, and the legacy MS-Dos 850 and 858 code pages, the Microsoft programmer decided for 8. Funny guy.

The glyph is supported in the usual code page for console apps on a Western machine. Which is 437, matches the legacy IBM character set. Having these kind of encoding disasters is why Unicode was invented. Sadly too late to rescue console apps, far too much code around that relied on the default MS-Dos code page.

Having Double.PositiveInfinity converted to "∞" is specific to Win10. It used to be "Infinity" in previous Windows versions. These kind of formats can normally be modified with Control Panel > Language > Change date, time, or number formats > Additional Settings button but the infinity symbol selection is not included in the dialog. Also not covered by the registry (HKCU\Control Panel\International), rather a big oversight. It is LOCALE_SPOSINFINITY in the native winapi. In a .NET program you can override it programmatically by cloning the CultureInfo and changing its NumberFormatInfo.PositiveInfinitySymbol property. Like this:

using System;
using System.Text;
using System.Threading;
using System.Globalization;

class Program {
    static void Main(string[] args) {
        Console.OutputEncoding = Encoding.GetEncoding(1252);
        var ci = (CultureInfo)Thread.CurrentThread.CurrentCulture.Clone();
        ci.NumberFormat.NegativeInfinitySymbol = "-Infinity";
        ci.NumberFormat.PositiveInfinitySymbol = "And beyond";
        Thread.CurrentThread.CurrentCulture = ci;
        Console.WriteLine(1 / 0.0);
        Console.ReadLine();
    }
}