Размер этого целого должен составлять 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)
cast.
Тестовая программа:
#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 в шестнадцатеричном значении, я получаю 0xFFF C C2EE вместо 0xFFF B C2EE, который вы получаете.У меня нет объяснения этому расхождению.Но вы можете видеть, что если промежуточный результат представляет собой 16-разрядную величину со знаком, вы можете получить в значительной степени тот результат, который видите.
Тогда возникает вопрос: почему там есть подписанная операция??У меня нет хорошего объяснения.Я думаю, что вам, возможно, придется взглянуть на ассемблерный код и понять, что происходит;Вы можете даже щекотать ошибку в компиляторе.