ДТ
Даниил Тетерин23 декабря 2018 г. 12:33

Простой калькулятор

На самом деле, задание действительно простое. Проблема есть лишь в выводе результата.

            double result;
            if(ui->radioButton_s->isChecked())
            {
                result=oper1+oper2;
                if (result>=qInf() or result<=-qInf())
                    ui->label_res->setText("Близость к бесконечности - ошибка");
                else
                    ui->label_res->setText(tr("%1").arg(result));

Участок кода, где результат выводиться в QLabel. Оба оператора, естественно, тоже double. Так вот, если при таком раскладе попытаться сложить слишком маленькие числа, то оно попросту начнет их округлять:

Если же чуть изменить метод вывода на

ui->label_res->setText(QString::number(result,'g',39));

, то результат перестанет округляться, но начнет появляться непонятный "мусор".

Что это за "мусор", почему он появляется, и как, в таком случае, нормально выводить ответ?

Рекомендуем хостинг TIMEWEB
Рекомендуем хостинг TIMEWEB
Стабильный хостинг, на котором располагается социальная сеть EVILEG. Для проектов на Django рекомендуем VDS хостинг.

Вам это нравится? Поделитесь в социальных сетях!

5
ДТ
  • 23 декабря 2018 г. 13:05

Через некоторое время я осознал, что проблема не столько в выводе, сколько при самом переводе из текста в число. Почему одно число, что было без плавающей точки, перевелось нормально, а второе так ужасно? Почему так происходит?

    Evgenii Legotckoi
    • 23 декабря 2018 г. 14:12
    • (ред.)

    Добрый день!

    Потому, что все компьютеры имеют ограничения по количеству разрядов для чисел с плавающей запятой. И всегда точность будет ограничена разрядностью.

    Существуют специальные библиотеки для проведения расчётов с числами, для которых требуется большая точность, чем позволяет разрядность ПК.

    Но в вашем случае не имеет смысла использовать подобную библиотеку, вы же не научные изыскания ведёте.

    В общем смиритесь, в определённых ситуациях всегда будет некоторое округления. Это особенность архитектуры ПК и ограничений с количество разрядов для каждой конкретной архитектуры. Единственное решение - это задавать разрядность для округления.

      ДТ
      • 23 декабря 2018 г. 15:39
      • (ред.)

      Извиняюсь, но это даже не округление, это ерунда какая-то. Почему при переводе строки "0.344" через .toDouble(), оно в итоге получает число 0.343999999999...? В смысле, ладно, хорошо, я смирился. Но когда преподаватель спросит "А почему КОНКРЕТНО так происходит?", что мне ему ответить?

        Evgenii Legotckoi
        • 23 декабря 2018 г. 15:53

        Нет никакой ерунды, просто архитектура компьютера не позволяет корректно хранить число с плавающей запятой 0.344

        Это дробь, а дроби имеют свойство быть бесконечными в плане разрядности. Компьютер просто не может корректно представить это число.

        Просто есть числа, чтобы корректно хранить которые требуется больше чем 64 разряда. Дроби как раз часто и относятся к таким числам.

        Почитайте про числа с плавающей точкой, мантиссу числа и т.д. а также про разрядность компьютеров и т.д. И попробуйте написать в двоичном виде число 0.344, сами увидите, что разрядов вам не хватит, поэтому и получите что-то вроде 0.343999999999..

          Evgenii Legotckoi
          • 23 декабря 2018 г. 16:08
          • (ред.)

          Я сам уже не помню, как правильно представлять дроби в двоичном представлении (давно этим не занимался в силу отсутствия необходимости), но по факту проблема в том, что двоичное представление ограничено количеством разрядов, а некоторые дроби для своего представления требуют больше разрядов, чем есть в распоряжении ПК, вот и выскакивают такие глюки. Это погрешность из разряда нормы. Если хотите более полного объяснения, то Вам потребуется прочитать про формирование числа с плавающей точкой и попытаться вручную, на листе, например, попытаться написать 0.344 в двоичном виде, например, для ограничения в 32 разряда. Когда разряды закончатся, то попытайтесь привести это число в десятичный вид, получите 0.343999999999..

            Комментарии

            Только авторизованные пользователи могут публиковать комментарии.
            Пожалуйста, авторизуйтесь или зарегистрируйтесь
            Г

            C++ - Тест 001. Первая программа и типы данных

            • Результат:66баллов,
            • Очки рейтинга-1
            t

            C++ - Тест 001. Первая программа и типы данных

            • Результат:33баллов,
            • Очки рейтинга-10
            t

            Qt - Тест 001. Сигналы и слоты

            • Результат:52баллов,
            • Очки рейтинга-4
            Последние комментарии
            G
            GoattRock3 сентября 2024 г. 20:50
            Как Копировать Файлы в Linux Задумывались когда-нибудь о том, как мы привыкли доверять свои вещи службам грузоперевозок? Сейчас такие услуги стали неотъемлемой частью нашей жизни, особенно когда речь идет о переездах между …
            ВР
            Влад Русоков2 августа 2024 г. 8:47
            Как Копировать Файлы в Linux Screenshot_20240802-065123.png
            d
            dblas55 июля 2024 г. 18:02
            QML - Урок 016. База данных SQLite и работа с ней в QML Qt Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
            k
            kmssr9 февраля 2024 г. 2:43
            Qt Linux - Урок 001. Автозапуск Qt приложения под Linux как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
            АК
            Анатолий Кононенко5 февраля 2024 г. 9:50
            Qt WinAPI - Урок 007. Работаем с ICMP Ping в Qt Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
            Сейчас обсуждают на форуме
            Evgenii Legotckoi
            Evgenii Legotckoi24 июня 2024 г. 22:11
            добавить qlineseries в функции Я тут. Работы оень много. Отправил его в бан.
            F
            Fynjy22 июля 2024 г. 11:15
            при создании qml проекта Kits есть но недоступны для выбора Поставил Qt Creator 11.0.2. Qt 6.4.3 При создании проекта Qml не могу выбрать Kits, они все недоступны, хотя настроены и при создании обычного Qt Widget приложения их можно выбрать. В чем может …
            BlinCT
            BlinCT25 июня 2024 г. 8:00
            Нарисовать кривую в qml Всем привет. Имеется Лист листов с тосками, точки получаны интерполяцией Лагранжа. Вопрос, как этими точками нарисовать кривую? ChartView отпадает сразу, в qt6.7 появился новый элемент…
            BlinCT
            BlinCT5 мая 2024 г. 12:46
            Написать свой GraphsView Всем привет. В Qt есть давольно старый обьект дял работы с графиками ChartsView и есть в 6.7 новый но очень сырой и со слабым функционалом GraphsView. По этой причине я хочу написать х…
            Evgenii Legotckoi
            Evgenii Legotckoi2 мая 2024 г. 21:07
            Мобильное приложение на C++Qt и бэкенд к нему на Django Rest Framework Добрый день. По моему мнению - да, но то, что будет касаться вызовов к функционалу Андроида, может создать огромные трудности.

            Следите за нами в социальных сетях