中间乘法的值通常需要两倍的位数作为输入。
// Example
int foo(int a, int b, int carry, int rem) {
int2x c; // Some type that is twice as wide at `int`
c = (int2x)a * b + carry;
return (int) (c % rem);
}
考虑到填充的可能性(似乎限制sizeof()
有效性)和非2的补码整数(限制位误),......
以下是否始终创建所需类型?
如果不是,如何编写至少一个合理的解决方案,即使不是完全可移植的?
#include <limits.h>
#include <stdint.h>
#if LONG_MAX/2/INT_MAX - 2 == INT_MAX
typedef long int2x;
typedef unsigned long unsigned2x;
#elif LLONG_MAX/2/INT_MAX - 2 == INT_MAX
typedef long long int2x;
typedef unsigned long long unsigned2x;
#elif INTMAX_MAX/2/INT_MAX - 2 == INT_MAX
typedef intmax_t int2x;
typedef uintmax_t unsigned2x;
#else
#error int2x/unsigned2x not available
#endif
[编辑]
合格:&#34;始终&#34;,如果long
,long long
和intmax_t
不起作用,则#error
即可。
我想知道的是,long
,long long
或intmax_t
中至少有1个会起作用,int2x
会被正确输入吗?
注意:以上假设xxx_MAX
是2的奇数幂减1.可能是一个好的假设?以上内容适用于至少2个平台,但这不是一个很好的可移植性测试。
答案 0 :(得分:4)
所有* _MAX常量都是(2^n)-1
形式的假设是有效的。请参阅 6.2.6类型表示,特别是 6.2.6.2整数类型,其中无符号整数类型的表示和有符号整数类型的正值完全定义为纯二进制,因此产生的最大值小于2的幂。
答案 1 :(得分:0)
对于signed
类型,最好只使用所考虑类型的值范围并进行比较。
首先,我们会尝试计算INT_MAX*INTMAX+INT_MAX
,以便在表达式a*b+carry
中获得最大可能值。通过转换为intmax_t
似乎是更合理的方法:
#define MAX_EXPRESSION ((intmax_t) INT_MAX * INTMAX + INT_MAX)
但是,如果MAX_EXPRESSION
的真实数学值大于INTMAX_MAX
,我们就会陷入困境。所以,让我们做一些数学来解决这个问题。
我们用 c = INT_MAX 和 m = INTMAX_MAX 表示。从数学上讲,我们想知道c*c+c <= m
。这导致了我们的不公平:c <= (m - c) / c
。由于除法是整数,因此结果被截断,因此在上一次操作中会丢失精确的数学运算。因此,我们必须写一个更精确的表达式,如下所示:`c&lt; = floor((m - c)/ c)+ fractional_part_of((m - c)/ c)。
如果c > floor((m - c) / c)
严格地,那么c >= floor((m - c) / c) + 1 > (m - c) / c
,其中划分是在数学意义上(具有精确的小数)。这给了我们c*c+c > m
,矛盾。因此,我们在数学上再次总结c <= floor((m - c) / c)
。
此表达式在 C 中更方便,因为 m - c 在使用类型intmax_t
计算时会给出正确的值(换句话说:它& #39;不是超出范围值。现在,除法(m - c) / c
将给出一个intmax_t
范围内的整数,尽管可能会被截断,因为除法是整数。实际上,它毫不犹豫地给了我们floor((m - c) / c
的价值。
这个comparisson给出了真,那么我们可以说c*c+c
可以在你的系统的最大有符号整数类型中表示,即intmax_t
。特别是:存在一个有符号整数类型,它能够表示系统中的值c*c+c
。
现在,在 C 代码中,我们可以写:
#define c INT_MAX
#define m INTMAX_MAX
#if (c <= (m - c) / c)
// There exists a signed type in your system
// such that INT_MAX*INTMAX+INT_MAX is representable
// as a value in that type.
#else
#error Sorry, the size of INT_MAX cannot be doubled...
#endif
一旦确定intmax_t
完成了这项工作,您就可以开始搜索具有解决问题的最小等级的有符号整数类型:我们可以再次询问我们为{{1}所做的相同问题},例如intmax_t
和long
:
long long