C# Double Type Precision Loss

Asked

Viewed 194 times

-1

Hello! I wrote a program in C# that converts the decimal separator from a comma string to a dot. For this, I used the Replace() method. The problem occurs when I try to convert the number (now with decimal point) to the double type. There is a kind of loss of precision. For example, if I have a string with 3.14 content and try to convert to double type, after the conversion the decimal separator gets lost and I get 314 as a result. Exemplary code:

using System;

namespace Testes {
    class Program {
        static void Main(string[] args) {
            string numero = "3,14";
            double valor;

            valor = double.Parse(numero.Replace(',', '.')); //Substitui o ponto pela vírgula
            Console.WriteLine("O valor após a conversão é {0}.", valor); 
            Console.ReadLine();
        }
    }
}

What I want is that after converting from double to string, the decimal value is not lost. I tried casting, but it didn’t work. Can someone please help me? Thank you!

  • Can you put your exit please. I took the test here and my exit was : O valor após a conversão é 3.14.

  • Did the answer answer answer what was asked? Something was left pending?

1 answer

0

This happens because of this adjustment of replacing the comma by point. The question code does not consider the application culture and this can be a big problem (just like now).

What happens there is that the culture of its application is not any culture that uses the point as a decimal separator. Most likely the application is using the Portuguese culture since this is inferred from the Operating System.

Unless you have a high control over data entry, the best way to do this conversion is to force the culture into the operation.

The input separates decimals with comma, it is possible to use the culture as Portuguese. The method double.Parse has an overload that allows this to be done.

double.Parse(numero, new CultureInfo("pt"));

Another common problem you may encounter is that the double.Parse will pop an exception whenever it fails to do the conversion. A good alternative is to use the double.TryParse. It also has an overload that allows you to inform the desired format of the conversion input. Below is an example of use:

if(!double.TryParse(entrada, NumberStyles.AllowDecimalPoint, new CultureInfo("pt"), out _)) {
    WriteLine($"Valor {entrada} é inválido");
}

In both cases it is still possible to use the NumberStyles to define conversion details.


Functional code making conversions in different cultures

using System;
using System.Globalization;
using System.Threading;
using static System.Console;

class MainClass 
{
    private static readonly CultureInfo CulturaEntrada = new CultureInfo("pt");

    public static void Main (string[] args) 
    {
        // Note que, dependendo da cultura que está aqui, a conversão pode ou não falhar
        FazerConversao();

        // Aqui, é garantido que funcione a sua conversão vai falhar
        // porque o separador de decimal da cultura é vírgula e não ponto
        Thread.CurrentThread.CurrentCulture = new CultureInfo("pt");
        FazerConversao();

        // Este método é independente da cultura da aplicação
        // Usando PT, EN ou FR a conversão sempre vai funcionar
        FazerConversaoCorretamente();

        Thread.CurrentThread.CurrentCulture = new CultureInfo("en");
        FazerConversaoCorretamente();

        Thread.CurrentThread.CurrentCulture = new CultureInfo("fr");
        FazerConversaoCorretamente();
    }

    public static void FazerConversao(string entrada = "3,14") 
    {
        double valor = double.Parse(entrada.Replace(',', '.'));
        ImprimirResultado(valor);
    }

    public static void FazerConversaoCorretamente(string entrada = "3,14") 
    {
        if(!double.TryParse(entrada, NumberStyles.AllowDecimalPoint, CulturaEntrada, out var valor)) {
            WriteLine($"Valor {entrada} é inválido");
            return;
        }

        ImprimirResultado(valor);
    }

    private static void ImprimirResultado(double valor) 
    {
        WriteLine($"O valor após a conversão é {valor}.");
        WriteLine($"A cultura sendo usada é {Thread.CurrentThread.CurrentCulture}\n");
    }
}

Browser other questions tagged

You are not signed in. Login or sign up in order to post.