#include <stdio.h>
#define PI 3.1415926535897932385
double dPI=PI;
float fPI=PI;
char *formstr="%sPI=%.18g(%d) \n";
int wmain(int argc, wchar_t **argv)
{
printf(formstr, "d", dPI, (int)dPI);
printf(formstr, "f", fPI, (int)fPI);
return 0;
}
printf and floating point types
Код:
Собственно, выводит этот код вот что:
Цитата:
dPI=3.1415926535897931(3)
fPI=3.1415927410125732(3)
Хотя, в соответствии с документацией, вторая printf должна выдать некий бред хотя бы в одном значении, по предполагаемой причине интерпретации 32-х битного float как 64-х битного double, и последующего съезжания адресов параметров. Я что то не понял наверно... Такое ощущение, что в данной ситуации парсер printf определяет размер аргумента по контенту, а не только по строке формата.
Сдается мне, что вы неправы. Бред получится, если вы, наоборот, попробуете вывести значение, которое выходит за пределы float, с флагом "%f".
Цитата: Alexander92
Сдается мне, что вы неправы. Бред получится, если вы, наоборот, попробуете вывести значение, которое выходит за пределы float, с флагом "%f".
Что то не понял смысла. :( Пример кода можно?
[QUOTE=MSDN]
%f - double. Signed value having the form [ – ]dddd.dddd, where dddd is one or more decimal digits. The number of digits before the decimal point depends on the magnitude of the number, and the number of digits after the decimal point depends on the requested precision.
%g - double. Signed value printed in f or e format, whichever is more compact for the given value and precision. The e format is used only when the exponent of the value is less than –4 or greater than or equal to the precision argument. Trailing zeros are truncated, and the decimal point appears only if one or more digits follow it.
[/QUOTE]
Соответственно, в вашем примере все правильно, никакого деления на 32- и 64-битные значения там нет.
Цитата: Alexander92
Соответственно, в вашем примере все правильно, никакого деления на 32- и 64-битные значения там нет.
Как это нет деления? Цифры то разные в обоих строках вывода (точность разная).
Решил усложнить эксперимент. Теперь вот такой код:
Код:
#include <stdio.h>
#define PI 3.1415926535897932385
double dPI=PI;
float fPI=PI;
char *formstr="%s: PI=%.18g, PI*2=%.18g, PI*3=%.18g \n";
int wmain(int argc, wchar_t **argv)
{
printf("sizeof(float) = %d, sizeof(double) = %d \n", sizeof(float), sizeof(double));
printf("sizeof(fPI) = %d, sizeof(dPI) = %d \n", sizeof(fPI), sizeof(dPI));
printf("sizeof(fPI*2) = %d, sizeof(dPI*2) = %d \n", sizeof(fPI*2), sizeof(dPI*2));
printf("sizeof(fPI*3) = %d, sizeof(dPI*3) = %d \n", sizeof(fPI*3), sizeof(dPI*3));
printf(formstr, "type = float", fPI, fPI*2, fPI*3);
printf(formstr, "type = double", dPI, dPI*2, dPI*3);
return 0;
}
#define PI 3.1415926535897932385
double dPI=PI;
float fPI=PI;
char *formstr="%s: PI=%.18g, PI*2=%.18g, PI*3=%.18g \n";
int wmain(int argc, wchar_t **argv)
{
printf("sizeof(float) = %d, sizeof(double) = %d \n", sizeof(float), sizeof(double));
printf("sizeof(fPI) = %d, sizeof(dPI) = %d \n", sizeof(fPI), sizeof(dPI));
printf("sizeof(fPI*2) = %d, sizeof(dPI*2) = %d \n", sizeof(fPI*2), sizeof(dPI*2));
printf("sizeof(fPI*3) = %d, sizeof(dPI*3) = %d \n", sizeof(fPI*3), sizeof(dPI*3));
printf(formstr, "type = float", fPI, fPI*2, fPI*3);
printf(formstr, "type = double", dPI, dPI*2, dPI*3);
return 0;
}
Но результат...
Код:
sizeof(float) = 4, sizeof(double) = 8
sizeof(fPI) = 4, sizeof(dPI) = 8
sizeof(fPI*2) = 4, sizeof(dPI*2) = 8
sizeof(fPI*3) = 4, sizeof(dPI*3) = 8
type = float: PI=3.1415927410125732, PI*2=6.2831854820251465, PI*3=9.4247782230377197
type = double: PI=3.1415926535897931, PI*2=6.2831853071795862, PI*3=9.4247779607693793
sizeof(fPI) = 4, sizeof(dPI) = 8
sizeof(fPI*2) = 4, sizeof(dPI*2) = 8
sizeof(fPI*3) = 4, sizeof(dPI*3) = 8
type = float: PI=3.1415927410125732, PI*2=6.2831854820251465, PI*3=9.4247782230377197
type = double: PI=3.1415926535897931, PI*2=6.2831853071795862, PI*3=9.4247779607693793
Ясно же видно, что данные разных размеров, но ничего не поехало. Мистика!!!
Вот если написать printf("%llu\n",0,1); -- выведется 4294967296.
Тут всё логично -- два 32-битных параметра обработались как одни 64-битный.
А обработка вывода все равно идет как double и для "%f", и для "%g", если верить MSDN.
Код:
int *pfPI;
pfPI=(int*)&fPI;
printf(formstr, "type = float", *pfPI, fPI*2, fPI*3);
pfPI=(int*)&fPI;
printf(formstr, "type = float", *pfPI, fPI*2, fPI*3);
...и вот оно, поехало.
Цитата:
sizeof(float) = 4, sizeof(double) = 8
sizeof(fPI) = 4, sizeof(dPI) = 8
sizeof(fPI*2) = 4, sizeof(dPI*2) = 8
sizeof(fPI*3) = 4, sizeof(dPI*3) = 8
type = double: PI=3.1415926535897931, PI*2=6.2831853071795862, PI*3=9.4247779607693793
type = float: PI=3.1415927410125732, PI*2=6.2831854820251465, PI*3=9.4247782230377197
type = float: PI=2.6815622281736349e+154, PI*2=-3.7857678997154335e-270, PI*3=8.8238517323821973e+175
Выходит, что компилятор, скрытно, конвертирует параметры для printf типа float в тип double.
А подсунь ему корректный float, но объявленный как int, он этого не сделает.
Код:
T var = va_arg(start, T);
лично я делаю вывод, что неравносильные преобразования типов внутри printf() вполне возможны, и доверять в этом вопросе нужно только и исключительно документации. А документация говорит, что и "%f", и "%g" трактуется как double, только в разном представлении.
Что за компилятор используется?
Цитата: Phodopus
Что за компилятор используется?
MSVC++ 2008
Default argument promotions (6.5.2.2. - 6)