Click here to Skip to main content
15,888,351 members
Home / Discussions / C#
   

C#

 
GeneralRe: Please tell me what is wrong with this simple C# program Pin
Brian_TheLion4-Mar-19 0:41
Brian_TheLion4-Mar-19 0:41 
GeneralRe: Please tell me what is wrong with this simple C# program Pin
OriginalGriff4-Mar-19 0:47
mveOriginalGriff4-Mar-19 0:47 
QuestionWhat is free alternative to microsoft bot framework? Pin
Nitin S3-Mar-19 21:14
professionalNitin S3-Mar-19 21:14 
AnswerRe: What is free alternative to microsoft bot framework? Pin
Richard MacCutchan3-Mar-19 21:46
mveRichard MacCutchan3-Mar-19 21:46 
AnswerRe: What is free alternative to microsoft bot framework? Pin
Eddy Vluggen4-Mar-19 0:36
professionalEddy Vluggen4-Mar-19 0:36 
QuestionC# Code converted from Java gives error using in Script Task in SSIS Pin
Member 141699203-Mar-19 18:42
Member 141699203-Mar-19 18:42 
AnswerRe: C# Code converted from Java gives error using in Script Task in SSIS Pin
OriginalGriff3-Mar-19 19:56
mveOriginalGriff3-Mar-19 19:56 
RantWhy is float to double conversion uniquely terrible? Pin
Eric Lynch3-Mar-19 2:21
Eric Lynch3-Mar-19 2:21 
UPDATE #2:
After going back to my original test number, and decoding it (literally) bit-by-bit, in each of the formats, before and after conversion, I'm baffled. The float->double conversion does exactly what I would do.

This makes it even more difficult to explain the outcome of my earlier test programs. The conversion itself seems accurate, but I'm clearly missing something. So, for now, I'm abandoning this post.

I'll come back and update it when I answer my own question. Though, that will probably be after I write an article explaining the ridiculous trivia of exactly what C# does with each of the floating-point formats. After which, I've really got to get a life Smile | :)

UPDATE #1:
After further consideration, I reassert that there is something uniquely, and inexplicably, terrible about the float->double conversion!

Some have suggested that this was something inherent with how floating point numbers are stored and not something uniquely terrible about float->double conversions. After a little bit of convincing, I concede that my original description did not exclude this possibility. While I intentionally chose a number with six decimal digits of precision (the limits of IEEE 754 binary32), perhaps unintentional bias led me to choose numbers that were particularly susceptible to this issue.

So, to disprove my original premise, I wrote a new test program (included at the end of this post). This program generated random numbers with between one and six digits of precision. To avoid bias towards any one of the three floating-point formats, it calculates the "ideal" text from an integral value using only string manipulation to format it as floating-point.

It then counts the number of times the ToString for the assigned values (decimal, double, and float) and converted values (decimal->double, decimal->float, double->decimal, double->float, float->decimal, and float->double) differ from this ideal value.

After running the program for 1 million cycles, the results were as follows:

decimal: 0
double: 0
float: 0
decimal->double: 0
decimal->float: 0
double->decimal: 0
double->float: 0
float->decimal: 0
float->double: 750741

I reassert that there is something uniquely, and inexplicably, terrible about the float->double conversion! As mentioned, the code is included at the end of this post.

ORIGINAL:
OK, this one drove me nuts!

I was developing some test cases and took a short cut. I used a float to represent some simple test data. I made the assumption that, since it has the least precision, anything simple that can be accurately represented in this format could be accurately represented in double or decimal (following conversion).

Now, to be clear, the value I chose (123.456) was only 6 significant decimal digits. This is well within the limits of the IEEE 754 binary32 / single format for accurate representation.

So, I went on my merry way and a bunch of my tests failed! The specific tests that failed all involved float to double conversions.

Imagine my surprise! I hadn't intended to test C# itself, but it appears I had. Again, the chosen value (123.456) is well within the required IEEE 754 accuracy limits: 6 decimal digits for single and 15 decimal digits for double.

So, I conducted a bunch of tests. Of the six possible floating-point conversions (decimal->double, decimal->float, double->decimal, double->float, float->decimal, and float->double), only float to double yielded unexpected results. Comically, even casting the float first to decimal and then to double yielded correct results.

So, I'll easily work around this problem, but this seems to be a bug!

Is anyone familiar with the exact technique C# uses to convert these values? Is it a hardware instruction (on most platforms) or is there code? If the former, then maybe different platforms would yield different results?

Basically, I want to figure out who to blame (Microsoft or Intel) Smile | :)

In case anyone thinks I'm imagining this issue, below is the test code I used to determine the exact characteristics of the problem. After each Console.WriteLine, I include a comment with the output it produced.

using System;

namespace FloatingPointConversion
{
  public class Program
  {
    public static void Main(string[] args)
    {
      decimal decimalValue = 123.456M;
      double doubleValue = 123.456D;
      float floatValue = 123.456F;

      Console.WriteLine($"{nameof(floatValue)} = {floatValue}");
      // floatValue = 123.456

      Console.WriteLine($"{nameof(decimalValue)} = {decimalValue}");
      // decimalValue = 123.456

      Console.WriteLine($"{nameof(doubleValue)} = {doubleValue}");
      // doubleValue = 123.456

      Console.WriteLine($"(float){nameof(decimalValue)} = {(float)decimalValue}");
      // (float)decimalValue = 123.456

      Console.WriteLine($"(double){nameof(decimalValue)} = {(double)decimalValue}");
      // (double)decimalValue = 123.456

      Console.WriteLine($"(decimal){nameof(doubleValue)} = {(decimal)doubleValue}");
      // (decimal)doubleValue = 123.456

      Console.WriteLine($"(float){nameof(doubleValue)} = {(float)doubleValue}");
      // (float)doubleValue = 123.456

      Console.WriteLine($"(decimal){nameof(floatValue)} = {(decimal)floatValue}");
      // (decimal)floatValue = 123.456

      Console.WriteLine($"(double){nameof(floatValue)} = {(double)floatValue}");
      // (double)floatValue = 123.456001281738

      Console.WriteLine($"(double)((decimal){nameof(floatValue)}) = {(double)((decimal)floatValue)}");
      // (double)((decimal)floatValue) = 123.456
    }
  }
}


using System;

namespace FloatingPointConversion
{
  public class Program
  {
    private static readonly decimal[] Divisors = new decimal[] { 1, 10, 100, 1000, 10000 };

    private static readonly string[] UnexpectedLabels = new string[]
    {
      "decimal", "double", "float", "decimal->double", "decimal->float", "double->decimal",
      "double->float", "float->decimal", "float->double"
    };

    private static readonly int[] UnexpectedCounts = new int[UnexpectedLabels.Length];
    private const int MaximumSixDigitNumber = 999999;
    private const int NumberOfAttempts = 1000000;

    public static void Main(string[] args)
    {
      RandomTest();
      for (int index = 0; index < UnexpectedLabels.Length; index++)
        Console.WriteLine($"{UnexpectedLabels[index]}: {UnexpectedCounts[index]}");
    }

    private static void RandomTest()
    {
      var random = new Random();

      for (int attempt = 0; attempt < NumberOfAttempts; attempt++)
      {
        int intValue = random.Next(MaximumSixDigitNumber + 1);
        int shift = random.Next(0, Divisors.Length);

        string idealText = GetIdealText(intValue, shift);

        decimal decimalValue = intValue / Divisors[shift];
        float floatValue = intValue / (float)Divisors[shift];
        double doubleValue = intValue / (double)Divisors[shift];

        if (decimalValue.ToString() != idealText)
          UnexpectedCounts[0]++;
        if (doubleValue.ToString() != idealText)
          UnexpectedCounts[1]++;
        if (floatValue.ToString() != idealText)
          UnexpectedCounts[2]++;
        if (((double)decimalValue).ToString() != idealText)
          UnexpectedCounts[3]++;
        if (((float)decimalValue).ToString() != idealText)
          UnexpectedCounts[4]++;
        if (((decimal)doubleValue).ToString() != idealText)
          UnexpectedCounts[5]++;
        if (((float)doubleValue).ToString() != idealText)
          UnexpectedCounts[6]++;
        if (((decimal)floatValue).ToString() != idealText)
          UnexpectedCounts[7]++;
        if (((double)floatValue).ToString() != idealText)
          UnexpectedCounts[8]++;
      }
    }

    private static string GetIdealText(int intValue, int shift)
    {
      string text = intValue.ToString();
      if (shift == 0)
        return text;

      return TrimTrailingZeros(text = shift >= text.Length ?
        "0." + text.PadLeft(shift, '0') : text.Insert(text.Length - shift, "."));
    }

    private static string TrimTrailingZeros(string text)
    {
      int length = text.Length;
      while(text[length - 1] == '0')
        length--;

      if (text[length - 1] == '.')
        length--;

      return length < text.Length ? text.Substring(0, length) : text;
    }
  }
}


modified 4-Mar-19 0:36am.

GeneralRe: Why is float to double conversion uniquely terrible? Pin
Richard MacCutchan3-Mar-19 2:40
mveRichard MacCutchan3-Mar-19 2:40 
GeneralRe: Why is float to double conversion uniquely terrible? Pin
Eric Lynch3-Mar-19 4:24
Eric Lynch3-Mar-19 4:24 
GeneralRe: Why is float to double conversion uniquely terrible? Pin
Richard MacCutchan3-Mar-19 5:14
mveRichard MacCutchan3-Mar-19 5:14 
GeneralRe: Why is float to double conversion uniquely terrible? Pin
Eric Lynch3-Mar-19 5:27
Eric Lynch3-Mar-19 5:27 
GeneralRe: Why is float to double conversion uniquely terrible? Pin
Richard MacCutchan3-Mar-19 5:45
mveRichard MacCutchan3-Mar-19 5:45 
GeneralRe: Why is float to double conversion uniquely terrible? Pin
Eric Lynch3-Mar-19 6:55
Eric Lynch3-Mar-19 6:55 
GeneralRe: Why is float to double conversion uniquely terrible? Pin
Eric Lynch3-Mar-19 18:28
Eric Lynch3-Mar-19 18:28 
GeneralRe: Why is float to double conversion uniquely terrible? Pin
Peter_in_27803-Mar-19 3:23
professionalPeter_in_27803-Mar-19 3:23 
GeneralRe: Why is float to double conversion uniquely terrible? Pin
Eric Lynch3-Mar-19 4:58
Eric Lynch3-Mar-19 4:58 
GeneralRe: Why is float to double conversion uniquely terrible? Pin
Eric Lynch3-Mar-19 7:07
Eric Lynch3-Mar-19 7:07 
GeneralRe: Why is float to double conversion uniquely terrible? Pin
Richard Deeming5-Mar-19 2:15
mveRichard Deeming5-Mar-19 2:15 
QuestionC# how to get all files from a directory that is inside the current project Pin
dolfijn300027-Feb-19 10:26
dolfijn300027-Feb-19 10:26 
AnswerRe: C# how to get all files from a directory that is inside the current project Pin
Richard Deeming27-Feb-19 10:43
mveRichard Deeming27-Feb-19 10:43 
QuestionForce Interface Implementation in Derived Classes? Pin
pr1mem0ver27-Feb-19 6:51
pr1mem0ver27-Feb-19 6:51 
AnswerRe: Force Interface Implementation in Derived Classes? Pin
Richard Deeming27-Feb-19 7:51
mveRichard Deeming27-Feb-19 7:51 
GeneralRe: Force Interface Implementation in Derived Classes? Pin
pr1mem0ver28-Feb-19 1:25
pr1mem0ver28-Feb-19 1:25 
GeneralRe: Force Interface Implementation in Derived Classes? Pin
Richard Deeming28-Feb-19 1:36
mveRichard Deeming28-Feb-19 1:36 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.