Ошибка округления в двойной строке - PullRequest
0 голосов
/ 24 ноября 2011

У меня есть double, который имеет фактическое значение (как видно из отладчика) val = 1.5530000000000002

, однако, если я напечатаю его как string.Format("{0}", val), я получу "1.553", которое является реалистичным значением, которое я ищу.

1.5530000000000002 происходит от некоторого API сокета, и я не могу изменить это.Но мне нужно 1.553 ..

что мне делать?

Обратите внимание, что я получаю тысячи таких в секунду.Я не могу позволить себе возиться с классом Math или , конвертируя их вперед и назад .какие-нибудь утешения?

Ответы [ 5 ]

4 голосов
/ 24 ноября 2011

Проблема в том, что double является значением с плавающей точкой, и для него может быть НЕВОЗМОЖНО в точности удерживать 1.5530000000000000. Тип decimal лучше для удержания точного значения, подобного этому.

Если вы не можете изменить double на decimal в API сокетов, то у вас нет выбора, кроме как использовать математику для решения этой проблемы. В этом случае вам нужно будет преобразовать double в decimal, а затем выполнить математические вычисления, чтобы отрегулировать точность, которую вы желаете.

Вот как вы можете легко это сделать:

double value = 1.5530000000000002;
decimal rounded = decimal.Round((decimal)value, 3);
0 голосов
/ 24 ноября 2011

Я решил повысить их до целых.Я могу сделать это, потому что я знаю, сколько значащих цифр в числе.

int real = (int)(dbl * multiplier);

Я уверен, что десятичные дроби будут медленнее просто потому, что у меня нет процессора x128 и шины памяти.Использование Math - это вопрос, который никогда не задавался.

извините за размытие с приведением к плаванию ранее.

РЕДАКТИРОВАТЬ ОК.Так что я понял, что ТАК теперь больше не бесплатно.Каждый вопрос требует теперь внимания, которое требует больших затрат времени ... Вот код, который отвечает, почему я не буду использовать десятичные дроби и математику.

class Program
{
    static void Main(string[] args)
    {
        Start();
        Console.ReadLine();                
    }

    static int TESTS = 10;
    static int LOOPS = 50000;

    static double d1 = 1.5530000000000002;
    static double d2 = 1.5531;

    static double dResult;
    static int iResult;
    static decimal cResult;

    static void Start()
    {
        // actual test
        for (int x = 0; x < TESTS; x++)
        {
            Stopwatch sw = new Stopwatch();

            long tick1, tick2, tick3;
            sw.Start();
            for (int j = 0; j < LOOPS; j++)
            {
                dResult = Math.Round(d1 / 2.0, 4);
                dResult = Math.Round(d2 / 2.0, 4);
            }
            sw.Stop();

            tick1 = sw.ElapsedTicks;

            sw.Restart();
            for (int j = 0; j < LOOPS; j++)
            {
                iResult = (int)(d1 / 2.0 * 10000.0);
                iResult = (int)(d2 / 2.0 * 10000.0);
            }
            sw.Stop();

            tick2 = sw.ElapsedTicks;

            sw.Restart();
            for (int j = 0; j < LOOPS; j++)
            {
                cResult = decimal.Round((decimal)d1, 4);
                cResult = decimal.Round((decimal)d2, 4);
            }
            sw.Stop();

            tick3 = sw.ElapsedTicks;

            Console.WriteLine("Math {0} Int {1} Decimal {2}", tick1, tick2, tick3);
        }
    }
}

первая часть - это математика, вторая - то, для чего я предназначениспользуйте (преобразование в int), а третий - в десятичные дроби.

Результаты на моем i7 выглядят следующим образом - 12K тиков, 700 тиков, 35K тиков соответственно.

0 голосов
/ 24 ноября 2011

Вы должны использовать Double?Если нет, то вы можете использовать Decimal.Round(val, 3), например.

0 голосов
/ 24 ноября 2011

По сути, вам необходимо использовать десятичный тип данных, а не двойной.Десятичные могут хранить точные значения, с точностью до его точности;двойной не может, следовательно, наблюдаемое поведение.

0 голосов
/ 24 ноября 2011

Класс Math более чем способен делать тысячи таких в секунду.Так что все, что вам нужно сделать, это Math.Floor(val, 3) или Math.Round(val, 3).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...