От новичка до гуру: Курсы программирования на CyberDuff

Какое значение с плавающей запятой заставляет sprintf_s() выдавать 1.#QO?

У меня есть некоторый код (устаревший встроенный c), который создает файл .csv с помощью некоторых вызовов sprintf. Иногда я вижу значения 1.#QO. Я пытался воспроизвести эти значения с условиями, которые должны давать отрицательную бесконечность, положительную бесконечность и NaN, но ни одно из них не дало мне волшебный результат 1.#QO. Так что же создает эту ценность?

... и да, я знаю, что явно что-то не так в математике, которая дает это значение, но понимание того, что это означает, поможет в усилиях по отладке.

[Edit 1] Фактическая строка, которая выполняет преобразование:

sprintf_s(txt, CSV_HEADER_SIZE, "%.3f", value);

где:

#define CSV_HEADER_SIZE (100)
char txt[CSV_HEADER_SIZE];

Я компилирую в MS Visual Studio 2008.

[Редактировать 2] Еще немного копания показывает, что 0xFFFFFFFF дает -1.#QO:

unsigned int i = 0xFFFFFFFF;
float* f = (float*)&i;
printf("%.3f", *f); // gives -1.#QO

.. и глядя на это в отладчике Visual Studio, он расширяется до -1.#QNAN00, так что похоже, что это, вероятно, специфичное для Microsoft представление NaN?


  • О какой строке sprintf() идет речь? 09.05.2011
  • Можете ли вы определить одно из значений, которые привели к этому результату, и отформатировать базовые данные с плавающей запятой, скажем, в шестнадцатеричном формате? Например, если это 4-байтовое число с плавающей запятой, вы можете printf("%X", value), а для 8-байтового числа вы можете сделать printf("%llX", value) в зависимости от платформы. Эта информация будет полезна. 09.05.2011
  • Не могли бы вы определить компилятор (и, если применимо, среду выполнения)? Этот конкретный вывод sprintf не был в стандарте в последний раз, когда я смотрел, так что, вероятно, он очень зависит от реализации. 09.05.2011
  • Я думаю, что 0xFFFFFFFF - это стандартное представление IEEE-754 для NaN, однако странный вывод этого числа кажется специфичным для Microsoft. Кроме того, имеет смысл, что вы получите это от деления на ноль. IEEE 754 NaN обсуждается здесь: en.wikipedia.org/wiki/NaN 10.05.2011
  • также см. примечание в статье в Википедии о qNaN (тихий, несигнализирующий NaN) 10.05.2011

Ответы:


1

"-1.#QO" равно "-1.#QNAN" после "округления" до 3 знаков после запятой. N округляется до O как «A» >= «5» и «N» + 1 == «O».

Точно так же ваш отладчик показывает "-1.#QNAN00", поскольку он печатает с 7 знаками и добавляет нули в конец.

QNaN — это тихий NaN.

10.05.2011
  • К такому выводу пришел и я. Странно, что он добавил O в конце. 10.05.2011
  • @JonCage: MSVC использует конечные нули для заполнения необходимых мест, а не обрабатывает QNAN иначе, чем обычные значения / значения, отличные от NaN. Места по умолчанию после запятой равны 6, поэтому объедините %f с NaN (как в вашем ответе) и помните, что strlen(#QNAN) равен 5... :) 10.05.2011
  • Последний символ — это буква (O), а не ноль (0). Я думаю, что это округление N до O, потому что если вы используете %.2f, вы получите -1.#R :-) 10.05.2011
  • @JonCage: А, я перепутал сообщения; в вашем ответе у вас есть -1.#QNAN0. Да, действительно, здесь он округляет N до O. Вот почему я поставил округление в кавычки, но я вижу, что это может быть неочевидно. Я расширю ответ. 10.05.2011

  • 2

    После долгого возни я могу окончательно сказать, что установка 4-байтового числа с плавающей запятой в 0x7FFFFFFF и передача его в sprintf_s со спецификатором формата %.3f - это то, что дало мне 1.#QO:

    const int bufSize = 100;
    char buf[bufSize];
    unsigned int i;
    float* f = (float*)&i;
    int retval;
    
    i = 0xFFFFFFFF;
    retval = sprintf_s(buf, bufSize, "%.3f\n", *f);
    printf("sprintf_s returned %d, converted val = %s", retval, buf); // == sprintf_s returned 7, converted val = -1.#QO
    retval = sprintf_s(buf, bufSize, "%f\n", *f);
    printf("sprintf_s returned %d, converted val = %s", retval, buf); // == sprintf_s returned 10, converted val = -1.#QNAN0
    
    i = 0x7FFFFFFF;
    retval = sprintf_s(buf, bufSize, "%.3f\n", *f);
    printf("sprintf_s returned %d, converted val = %s", retval, buf); // == sprintf_s returned 6, converted val = 1.#QO
    retval = sprintf_s(buf, bufSize, "%f\n", *f);
    printf("sprintf_s returned %d, converted val = %s", retval, buf); // == sprintf_s returned 9, converted val = 1.#QNAN0
    

    ... кажется, что спецификатор формата %.3f обрезал результат NAN, поэтому то, что должно было быть 1.#QNAN0, было сокращено до 1.#QO.

    10.05.2011

    3

    Небольшое гугление указывает на ошибку деления на 0. Хотя я бы ожидал чего-то другого, если бы это было так. Тем не менее, похоже, что это специфично для MS/Visual C.

    09.05.2011
  • Внизу этой записи в блоге: journal.joshburton.com/2008/ 01/1qo-value-of-doom.html 09.05.2011

  • 4

    Вы проверили, вернул ли sprintf_s() ошибку? Если это так, вы не должны использовать результат. Поскольку код не выглядит так, как будто вы проверили, я думаю, вам следует выполнить эту проверку. На самом деле, если вы не проверите результат одной из функций *_s(), вас ждут неприятности.

    09.05.2011
  • Из документации я видел [msdn .microsoft.com/en-us/library/ce3zzk1k%28v=vs.80%29.aspx] проблема возникает только в том случае, если возвращается <= 0 (ошибка или символы не записаны)? Но поскольку значение выписывается вроде бы нормально, я сомневаюсь, что проблема именно в этом. Фактический код, который мы используем, немного сложнее. Я просто сократил его, чтобы сделать его более кратким (возможно, слишком много?). Мы проверяем возвращаемые значения на практике. 10.05.2011
  • Если вы вообще проверяете результат, то, вероятно, у вас все в порядке. Из вашего «фрагмента» не было ясно, проверяли ли вы возвращаемое значение. Я получил «404 не найдено» по вашей ссылке; но это сработало. 10.05.2011
  • Справедливое замечание и стоит проверить, что я не пропустил этот момент :-) 10.05.2011
  • Новые материалы

    Отслеживание состояния с течением времени с дифференцированием снимков
    Время от времени что-то происходит и революционизирует часть моего рабочего процесса разработки. Что-то более забавное вместо типичного утомительного и утомительного процесса разработки. В..

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

    Игра в прятки с данными
    Игра в прятки с данными Я хотел бы, чтобы вы сделали мне одолжение и ответили на следующие вопросы. Гуглить можно в любое время, здесь никто не забивается. Сколько регионов в Гане? А как..

    «Раскрытие математических рассуждений с помощью Microsoft MathPrompter и моделей больших языков»
    TL;DR: MathPrompter от Microsoft показывает, как использовать математические рассуждения с большими языковыми моделями; 4-этапный процесс для улучшения доверия и рассуждений в математических..

    Раскройте свой потенциал в области разработки мобильных приложений: Абсолютная бесплатная серия
    Глава 6: Работа в сети и выборка данных Глава 1: Введение в React Native Глава 2: Основы React Native Глава 3: Создание пользовательского интерфейса с помощью React Native Глава 4:..

    Все о кейсах: Camel, Snake, Kebab & Pascal
    В программировании вы сталкивались с ними при именовании переменной, класса или функции. Поддержание согласованности типов и стилей случаев делает ваш код более читабельным и облегчает совместную..

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