Неожиданный результат в mspgcc
Я написал простой код на C, но когда я портирую его на mspgcc, он не дает мне правильного значения. Это часть моего кода:
unsigned short int xk=3588, yk=47541, yk1, sig=10, de=1;
unsigned long int xk1;
xk1=( xk+(sig*(yk-xk)*de));
yk1=xk1 % 65535;
результат, который я ожидаю xk1=443118
а также yk1=49908
, но в mspgcc это дает мне xk1=yk1=49902
, Я не знаю, где вина может быть в выборе типа?
редактировать
это мой полный код
#include <stdio.h>
#include "uart1.h"
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <math.h>
int putchar(int c)
{
return uart1_putchar(c);
}
int main(void)
{
//variables
unsigned short int xk=3588, yk=47541, yk1, sig=10, de=1;
unsigned long xk1;
uart1_init();
xk1=( xk+(sig*((unsigned long)yk-xk)*de));
yk1=xk1 % 65536;
printf("xk1=%6lx\t\n,",xk1);
printf("yk1=%u\t\n,",yk1);
}
1 ответ
Размер целого числа должен составлять 16 бит с этим компилятором, который является вполне допустимой системой.
Вы ожидали xk1
быть 443118. 443118 % 65536 - это 49902.
Так как расчет:
unsigned short int xk=3588, yk=47541, yk1, sig=10, de=1;
unsigned long int xk1;
xk1=( xk+(sig*(yk-xk)*de));
включает только unsigned short
ценности, они повышены до unsigned int
то результат вычисляется как unsigned int
и, наконец, это значение присваивается unsigned long
, Но лишние биты давно потеряны... вычисление было выполнено в 16-битной беззнаковой арифметике.
эксперимент
Проводится на 64-битной машине RHEL5 (AMD x86/64) с GCC 4.1.2. Чтобы имитировать 16-разрядное целочисленное вычисление, я свободно добавил (вторую копию) выражение с ((unsigned short)(...))
слепки. Двойное умножение получает только один бросок; результат не изменяется независимо от порядка, в котором выполняются два умножения (вдвойне нет, поскольку один из умножителей равен 1). И я включил (третью копию) выражение с (unsigned long)
бросать.
Тестовая программа:
#include <stdio.h>
int main(void)
{
unsigned short int xk=3588, yk=47541, sig=10, de=1;
unsigned long int xk1;
xk1 = (xk+(sig*(yk-xk)*de));
printf("No Cast: %6lu = (%u+(%u*(%u-%u)*%u))\n", xk1, xk, sig, yk, xk, de);
xk1 = ((unsigned short)(xk+((unsigned short)(sig*((unsigned short)(yk-xk))*de))));
printf("US Cast: %6lu = (%u+(%u*(%u-%u)*%u))\n", xk1, xk, sig, yk, xk, de);
xk1 = (xk+(sig*((unsigned long)yk-xk)*de));
printf("UL Cast: %6lu = (%u+(%u*(%u-%u)*%u))\n", xk1, xk, sig, yk, xk, de);
return 0;
}
Выход:
$ gcc -Wall -Wextra -g -O3 -std=c99 xx.c -o xx && ./xx
No Cast: 443118 = (3588+(10*(47541-3588)*1))
US Cast: 49902 = (3588+(10*(47541-3588)*1))
UL Cast: 443118 = (3588+(10*(47541-3588)*1))
$
Я думаю, что второе, почти нечитаемое выражение точно отражает (или достаточно точно отражает) способ, которым 16-битный компилятор будет оценивать выражение - и согласуется с тем, что вы видели.
Результат (47541-3588) равен 43953. Результат (10 * 43953) % 65536 равен 46314. Добавьте 3588, и результат, как и должно быть, 49902.
Я также добавил (unsigned long)
приведение к yk
и побежал выражение. Может быть, для полной точности с вашей машиной с 32-битным unsigned long
Я должен был использовать unsigned int
, но результат не меняется. Я не знаю, откуда у вас альтернативная ценность - мне нужно увидеть вашу полную рабочую программу (аналогичную моей), чтобы получить какие-либо идеи по этому поводу. Выглядит так, как будто у вас какая-то часть вычислений "пошла в минус", оставляя вас с большими (положительными) значениями без знака, но нет очевидного оправдания для того, чтобы вычисление пошло в минус.
Взяв код из комментария:
#include <stdio.h>
// -unused- #include "uart1.h"
// -unused- #include <stdlib.h>
// -unused- #include <stdint.h>
// -unused- #include <string.h>
// -unused- #include <math.h>
// -unused- int putchar(int c) { return uart1_putchar(c); }
int main(void)
{
//variables
unsigned short int xk=3588, yk=47541, yk1, sig=10, de=1;
unsigned long xk1;
// -not-needed-in-demo uart1_init();
xk1=( xk+(sig*((unsigned long)yk-xk)*de));
yk1=xk1 % 65535;
//printf("xk1=%6lx\t\n,",xk1);
//printf("yk1=%u\t\n,",yk1);
printf("xk1 = %6lx = %6u\n", xk1, xk1);
printf("yk1 = %6x = %6u\n", yk1, yk1);
}
65535 должно быть 65536. Вкладка в конце строки не нужна, как и запятая в начале следующей (но это чистая косметика).
Более серьезная (но несущественная для рассматриваемой проблемы, потому что она не используется), <stdio.h>
определяет функцию (и обычно макрос тоже) с именем putchar()
, Вы, вероятно, не должны определять свою собственную функцию с именем putchar
, но если вам нужно, вы обычно должны отменить определение макроса (при условии, что он есть) из <stdio.h>
, Я допускаю, что код, скомпилированный на моей машине, в порядке - не связывался, но это было ожидаемо; однажды, может быть, я буду отслеживать, что putchar()
действительно есть на этой машине.
Показанный код дает правильный / ожидаемый ответ.
Единственный способ, с помощью которого я могу увидеть наблюдаемое некорректное поведение, это то, где я удалил лишний код:
#include <stdio.h>
int main(void)
{
unsigned short int xk=3588, yk=47541, yk1, sig=10, de=1;
unsigned long xk1;
xk1=( xk+(sig*((unsigned long)yk-xk)*de));
yk1=xk1 % 65536;
printf("xk1= %6lx = %6lu\n", xk1, xk1);
printf("yk1= %6x = %6u\n", yk1, yk1);
xk1=( xk+(sig*((short)yk-xk)*de));
yk1=xk1 % 65536;
printf("xk1= %6lx = %6lu\n", xk1, xk1);
printf("yk1= %6x = %6u\n", yk1, yk1);
}
При запуске на моей 64-битной машине (в настоящее время MacOS X 10.6.7 с GCC 4.6.0) я получаю:
xk1= 6c2ee = 443118
yk1= c2ee = 49902
xk1= fffffffffffcc2ee = 18446744073709339374
yk1= c2ee = 49902
Игнорируя 8 дополнительных F в шестнадцатеричном значении, я получаю 0xFFFC C2EE, а не 0xFFFB C2EE, который вы получаете. У меня нет объяснения этому расхождению. Но вы можете видеть, что если промежуточный результат представляет собой 16-разрядную величину со знаком, вы можете получить в значительной степени тот результат, который видите.
Тогда возникает вопрос: почему там подписанная операция? У меня нет хорошего объяснения. Я думаю, что вам, возможно, придется взглянуть на ассемблерный код и понять, что происходит; Вы можете даже щекотать ошибку в компиляторе.