你想做的是模运算。你的 2 的补码机器已经用整数数学做到了这一点。因此,通过将您的值映射到 2 的补码算术,您可以免费获得 modolo 操作。
诀窍是将您的角度表示为 0 到 1-epsilon 之间 360 度的分数。当然,那么您的恒定角度必须以类似方式表示,但这应该不难;它只是我们可以隐藏在转换函数(呃,宏)中的一点数学。
这个想法的价值在于,如果你添加或减去角度,你会得到一个你想要的小数部分和你想要丢弃的整数部分的值。如果我们将分数表示为 32 位定点数,二进制点为 2^32(例如,在通常被认为是符号位的左侧),分数的任何溢出都会简单地从免费的 32 位值。所以,你做所有的整数数学,“溢出”删除是免费的。
所以我会重写你的代码(保留度数乘以 10 的概念):
typedef unsigned int32 angle; // angle*3600/(2^32) represents degrees
#define angle_scale_factor 1193046.47111111 // = 2^32/3600
#define make_angle(degrees) (unsigned int32)((degrees%3600)*angle_scale_factor )
#define make_degrees(angle) (angle/(angle_scale_factor*10)) // produces float number
...
angle a = make_angle(100); // compiler presumably does compile-time math to compute 119304647
angle b = make_angle(200); // = 238609294
angle c = a - b; // compiler should generate integer subtract, which computes 4175662649
#if 0 // no need for this at all; other solutions execute real code to do something here
if (c < 0) // this can't happen
{ c += 3600; } // this is the wrong representation for our variant
#endif
// speed doesn't matter here, we're doing output:
printf("final angle %f4.2 = \n", make_degrees(c)); // should print 350.00
我还没有编译和运行这段代码。
使这个度数乘以 100 或乘以 1 非常容易;修改 angle_scale_factor。如果你有一台 16 位机器,切换到 16 位同样容易;如果您有 32 位,但仍只想进行 16 位数学运算,则需要将要打印的值屏蔽为 16 位。
这个解决方案还有一个很好的属性:您已经记录了哪些变量是角度(并且有有趣的表示)。OP 的原始代码只是将它们称为整数,但这不是它们所代表的;未来的维护者会对原始代码感到惊讶,尤其是当他发现减法与变量隔离时。