1. C# / Говнокод #4947

    +118

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    10. 10
    11. 11
    12. 12
    13. 13
    14. 14
    15. 15
    16. 16
    17. 17
    18. 18
    static double SingleToDouble(Single v)
    {
        return double.Parse(v.ToString());
    }
    
    static void Scan()
    {
        double q = 0.0;
        while (q <= 10.0)
        {
            Single s = (Single)q;
            Double d = SingleToDouble(s);
    
            if (d == q)
                MessageBox.Show(q.ToString());
            q = q + 0.1;
        }
    }

    народ, кто-нибудь знает чем можно заменить код "return double.Parse(v.ToString());" в SingleToDouble?
    "return v;" не подходит - на экран выводятся только 0, 0.5 и 4.5. А нужно чтобы все выводились 0, 0.1, 0.2 ... 0.9.

    Запостил: 4eburashka, 16 Декабря 2010

    Комментарии (49) RSS

    • > А нужно чтобы все выводились 0, 0.1, 0.2 ... 0.9.

      С чего бы? 0.1 не может быть точно представимо в компьютере, поэтому при конвертации туда-сюда такая фигня получается. Это нормально.

      if (d == q)
      замени на
      if abs(d-q) < eps
      Ответить
    • не используйте точные сравнения для плавающей точки

      или не используйте плавающую точку
      Ответить
    • static double SingleToDouble(Single v)
      {
          return Convert.ToDouble(v);
      }

      TarasB объяснил суть проблемы, так что с этим кодом тоже не заработает.
      Ответить
    • Пля... Достаточно одной строки:
      q.ToString("0.#")
      Ответить
    • Спасибо за ответы.
      еще немного подробнее о проблеме:
      имеется double: q=1.1;
      мы присваиваем: Single s=(Single)q;
      а потом обратно в Double: double g=s;
      получается, что g=0.10000000149011612, т.е. добавляются левые 0.00000000149011612.
      Есть ли более "приличный" способ эти левые числа отбросить, кроме как double.Parse(q.ToString("0.########"))?
      Ответить
      • Зачем их отбрасывать?
        Просто запомни: никогда не сравнивай вещественные числа оператором "равно".
        Ответить
        • Объясню зачем это нужно (абстрактно).
          В результате каких-то расчетов с плавающей запятой получается результат, который сохраняется в файл в 4-х байтном формате, т.е. Single. Формат файла строго регламентирован.
          Потом, когда этот результат загрузится из файла (допустим другой программой) и преобразуется в double для дальнейших расчетов, то добавляются левые числа! Вот я и пытаюсь найти какое-нибудь средство, чтобы от левых чисел избавиться.
          Ответить
          • Если тебе нужны только тысячные, то

            d := round(d*1000)*0.001

            А если тебе нужно хранить точные значение, то терпи что есть.
            Ответить
            • А нету какой-нибудь функции как в MSSQL округление Round, где задаешь сколько тебе чисел после запятой надо?
              Ответить
              • http://msdn.microsoft.com/en-us/library/ms175003.aspx

                ROUND (numeric_expression , length [ ,function ])
                Ответить
                • У Round есть 8 перегрузок на все случаи жизни!!! ))))
                  Ответить
              • Зачем округлять? ЗАЧЕМ?!!
                Ничего лишнего ниоткуда не берётся! Это вещественные числа! А ну марш читать про них!
                Они представлены в памяти так, как представлены. Не трогай их! И лишь при показе пользователю используй формат.
                Ответить
                • показать все, что скрытоТо есть по-вашему
                  0.10000000149011612 и 0.10000000000000000
                  одно и то же? Мы же точность увеличили с float до double.
                  Ответить
                  • показать все, что скрытоВсе-таки очень интересно, в чем же я не прав. Ответ "-" не столь информативен...
                    Ответить
                    • Ну просто надо знать, что вещественные числа сравнивать через оператор сравнения нельзя.
                      Ответить
                      • Как раз-таки с этим я спорить не собирался... Вопрос был в корректности преобразования Single > Double. Впрочем, koodeer ниже уже все пояснил.
                        Ответить
                • Вот зачем, потому что они не равны:

                  double v1 = 1.1;
                  double v2 = (Single)v1;
                  v1 *= 10000000000;
                  v2 *= 10000000000;

                  и теперь у нас
                  v1 = 11000000000.0
                  v2 = 11000000238.418579
                  Ответить
                  • Где гарантия, что округляя числа, ты не обрежешь нужное значение?

                    Какой смысл в двойной точности, если на промежуточном этапе данные сохраняются в одинарной? Это говноархитектура! Своим говнокодом ты пытаешься заткнуть дыру говноархитектуры приложения.
                    Ответить
                    • Плюсую, согласен.
                      Ответить
                    • >Какой смысл в двойной точности, если на промежуточном этапе данные сохраняются в одинарной?

                      Совершенно нормально для вычислительной математики, когда точность вычислений у вас выше, чем точность результата. Для задач оптимизации максимальная точность результата -- это корень от точности вычислений (достаточно очевидно это, если с математическим анализом знакомы).
                      Кроме того, данные могут сохранятся где-то в определённом формате, независящем от программы, производящей вычисления.
                      Ответить
                      • Вот. А здесь точность исходных данных ниже точности предполагаемого результата.
                        Ответить
                        • Этот разговор уже лишён смысла, ибо все необходимые советы уже даны.

                          Но "говноархитектура" здесь совершенно не очевидна. (далее С++) Скажем, закладывая float в метод Рунге-Кудта второго порядка и рассчитывая во float ответ будет колебаться (то есть фазовая траектория будет "дышать"). А если внести float, рассчитать в double, и снова конвертировать во float, то ответ не изменится (всегда один и те же числа будут получаться, фазовая траектория во float стабильна, но "дышит" в double). Это как раз связано с тем, что начальные и конечные данные имеют точность ниже того, чем нужно считать.

                          Насколько я понимаю, в процессорах Intel даже существует дополнительное ещё более длинное число, чем double, которое используется в выражениях содержащих плавающую точку, чтобы получать, до некоторой степени, всегда один и тот же результат выражения в пределах точность double.
                          Ответить
                          • > Насколько я понимаю, в процессорах Intel даже существует дополнительное ещё более длинное число, чем double

                            long double штоле?
                            Ответить
                            • Ну, например, Extended в Delphi.
                              Ответить
                              • Ну и я про то же.
                                Просто он так назвал, как будто это новая сверхсекретная технология Интела.
                                Ответить
                            • Полагаю, что long double это отдельная "песня", которая содержит свои сложности и заковырки. И, насколько я понимаю, не имеет отношения к попыткам создать предсказуемую математику на уровне аппаратном. Внутреннее представление следует избирать из каких-то тонких соображений, в то время, как long double может быть предоставлен компилятором, создающим машинный код для поддержки расширенной арифметики. MSVC++ не предоставляет расширения для long double, и это тоже нормально.
                              Ответить
                            • The most common extended-precision format is currently the 80-bit format first used in the Intel 8087 math coprocessor (and later in the Motorola 68881)

                              http://en.wikipedia.org/wiki/Extended_precision
                              Ответить
                              • 80-битный формат называется long double в Си и extended в BP/Delphi. Проблема в том, что в некоторых реализациях компиляторов он отсутствует, а в некоторых в памяти занимает 12 байт вместо 10.
                                Ответить
                                • в сях кончились кейворды, вот и получился long long long long hard signed char
                                  а сам формат нативный, поэтому и длина неправильная получилась
                                  Ответить
                                • >в некоторых в памяти занимает 12 байт вместо 10.
                                  А с чем это связано? С выравниванием?
                                  Ответить
                          • > метод Рунге-Кудта
                            facepalm.for
                            Ответить
                  • Вещественные числа сравнивать через оператор сравнения нельзя!!!

                    ВЕЩЕСТВЕННЫЕ ЧИСЛА СРАВНИВАТЬ ЧЕРЕЗ ОПЕРАТОР СРАВНЕНИЯ НЕЛЬЗЯ!!!

                    ВЕЩЕСТВЕННЫЕ ЧИСЛА СРАВНИВАТЬ ЧЕРЕЗ ОПЕРАТОР СРАВНЕНИЯ НЕЛЬЗЯ!!!

                    ВЕЩЕСТВЕННЫЕ ЧИСЛА СРАВНИВАТЬ ЧЕРЕЗ ОПЕРАТОР СРАВНЕНИЯ НЕЛЬЗЯ!!!

                    ВЕЩЕСТВЕННЫЕ ЧИСЛА СРАВНИВАТЬ ЧЕРЕЗ ОПЕРАТОР СРАВНЕНИЯ НЕЛЬЗЯ!!!
                    Ответить
                    • КЭП, лучше скажи как избавиться от левых чисел при конвертации из Single в Double?
                      Какого хрена у меня погрешность возникает, когда я в более точное представление конвертирую?
                      Ответить
                      • Погрешность у тебя не возникает, она остаётся тебе в наследство от Single.
                        То есть Single сам по себе хранит мало знаков после запятой, но для него погрешность 1Е-7 нормальна. То есть число типа 1.111111111 при выводе заменяется на 10.0
                        А вот те же 1Е-7 для Double уже не погрешность представления, и 1.111111111000000 выводится как есть.
                        Ответить
                        • Спасибо. Т.е. я понимаю, что вот это "double.Parse(v.ToString());" лучше чем "Convert.ToDouble(v);", потому что во втором случае погрешность как была так и будет, а в первом она иногда округляется до нормального значения. как пример число 1.1.
                          Ответить
                          • Округление и там и там, но через Convert быстрее.
                            // то есть через Math.Round(), опечатка.
                            Ответить
                          • Нафига тебе вообще убирать эту погрешность? Убирай только при выводе, тебе же сказали!
                            Ответить
                          • И вообще, конвертация через строку - это полный говнокодизм, связанный с полным непониманием внутренней структуры вещественного числа.
                            Если неймётся, то используй round(x*100000)*0.00001
                            но лучше так не делай.
                            Лучше почитай книжки или википедию http://ru.wikipedia.org/wiki/Числа_с_плавающей_запятой
                            Ответить
    • говнокод катится в сраное stackoverflow с VB и ламерами

      PS: за обращение "народ" не стоя на броневичке хочется отдельно уебать
      Ответить

    Добавить комментарий