LINUX.ORG.RU

«Странное» поведение std::cout.setf (на самом деле нет)

 ,


0

2

Столкнулся с одной проблемой, но пока писал сюда, разобрался.

Сегодня запустил в Linux ранее написанную небольшую утилитку (писал в Windows с использовванием MinGW64). При это заметил, что вывод результата крайне странный: результат функции класса почему-то выводится в «hex». Сначала решил, что может чего намудрил внутри функции, но в ней число вычислялось нормально. Методом «научного» тыка выяснил, что проблема связана с std::cout.setf, так как в процессе вывода данных я, в зависимости от потребностей, меняю формат вывода.

Набросал небольшой пример, который демонстрирует проблему:

#include <iostream>

/* g++ -Wall -std=c++11 ./main.cpp  */

int main() {

    double test_d = -0.0010532140082682021;

    std::cout.setf(std::ios::scientific);
    std::cout << "test_d = " << test_d << std::endl;
    
    std::cout.setf(std::ios::fixed);
    std::cout << "test_d = " << test_d << std::endl;

return 0;
}

Можно и без -std=c++11, результат вывода тот же:

test_d = -1.053214e-03
test_d = -0x1.1417fee28283fp-10

вместо второго числа ожидается -0.001053.

Ну так вот, как оказалось, просто переключиться на fixed формат недостаточно, так как scientific при это не отключается, а в сочетании с ним, результат будет выводиться в HEX (http://en.cppreference.com/w/cpp/io/ios_base/setf):

scientific - generate floating point types using scientific notation, 
or hex notation if combined with fixed: see std::scientific

то есть перед вызовом std::cout.setf(std::ios::fixed) нужно сначала вызвать

std::cout.unsetf(std::ios::scientific);

Осталось понять, почему в MinGW64 (не помню какой версии), работает иначе.

★★★★★

Последнее исправление: grem (всего исправлений: 2)

Возможно баг в стандартной библиотеке предоставляемой MinGW

Даже страдающий синдромом Дауна (насколько это применимо к программе) VC++ выдает результат как в стандарте: http://rextester.com/UGZF3169

KennyMinigun ★★★★★
()
Последнее исправление: KennyMinigun (всего исправлений: 2)
Ответ на: комментарий от DELIRIUM

Да, но о таком поведении не везде пишут. Я из некоторых описаний наоборот решил, что они друг друга заменяют.

Здесь http://www.cplusplus.com/reference/ios/fixed , например, об этом не упоминают, покрайней мере для c++98, да и для c++11не похоже, что явно об этом пишут. Скорее всего мне нужен был флаг floatfield, проверю, переключает ли он с scientific.

grem ★★★★★
() автор топика
Последнее исправление: grem (всего исправлений: 1)
Ответ на: комментарий от DELIRIUM

Вот кому верить? Здесь заявляют, что

ios::fixed fixed if this is set, floating point numbers are printed in fixed-point notation. When this flag is set, ios::scientific is automatically unset

ios::scientific scientific if this is set, floating point numbers are printed in scientific (exponential) notation. When this flag is set, ios::fixed is automatically unset

grem ★★★★★
() автор топика

MinGW64 (не помню какой версии)

Скорее всего, старее, чем 5.0.0.

utf8nowhere ★★★
()
Ответ на: комментарий от utf8nowhere

Ну так вспоминай.

Скорее всего, старее, чем 5.0.0.

Спасибо. Да, 4.9.3 была. В 5.4.0 уже тоже выводит во втором случае в hex.

http://eel.is/c draft/floatfield.manip#7.sentence-2

C++ 2003 gives no meaning to the combination of fixed and scientific

Вот здесь не понял. В 2003 стандарте поведение поменяли?

grem ★★★★★
() автор топика
Ответ на: комментарий от utf8nowhere

Странно, я флаг -std=c++98 выставлял тоже, результат тот же. Ну да ладно, они постоянно что-то меняют: на работе у коллеги фортрановский код не собирался с gcc 4.9.3, а с 6.3.0 собирался и работал.

grem ★★★★★
() автор топика
Ответ на: комментарий от grem

я флаг -std=c++98 выставлял тоже, результат тот же

Ну значит в этой части библиотеки не проверяется версия стандарта. Безусловно проапгрейдили поведение до 11-й.

utf8nowhere ★★★
()
Ответ на: комментарий от utf8nowhere

Похоже на то, проверил с gcc-4.7.2 (Debian Wheezy Astra Orel), пример выводит всегда в десятичной форме, независимо от флага -std={c++98,c++03,c++11}. Аналогично в CentOS 7 с gcc-4.8.5 для всех флагов -std={c++98,c++03,c++11}

Ну значит в этой части библиотеки не проверяется версия стандарта. Безусловно проапгрейдили поведение до 11-й.

Вот «нехорошие человеки» :(

grem ★★★★★
() автор топика
Ответ на: комментарий от utf8nowhere

А если не использовать setf, то вывод будет без HEX и в нвоых компиляторах:

#include <iostream>

int main() {
    
    double x = -0.0010532140082682021;
    std::cout << "x = " << std::fixed << x << std::endl;
    std::cout << "x = " << std::scientific << x;

return 0;
}

Вывод:

x = -1.053214e-003
x = -0.001053
grem ★★★★★
() автор топика
Ответ на: комментарий от grem

Потому что см. http://en.cppreference.com/w/cpp/io/ios_base/setf

(1) эта перегрузка делает побитовое «или», т.е. сохраняет остальные флаги
(2) манипуляторы эквивалентны вызову второй перегрузки (http://eel.is/c draft/floatfield.manip), а она "Clears the formatting flags under mask, and sets the cleared flags to those specified by flags."

utf8nowhere ★★★
()
Ответ на: комментарий от utf8nowhere

Спасибо. Так то оно понятно, что это само по себе разные вещи. Нужно будет не забыть о разном поведении.

grem ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.