组合简便算法 (long long 与__int64)

本文介绍了一种有效的组合数计算方法,避免了直接计算阶乘可能导致的溢出问题。通过简化计算过程并采用适当的技巧,确保了即使在输入值较大时也能得到正确的结果。

求组合很简单:

#include<stdio.h>
__int64 zu(int n)
{
    __int64 s = 1;
    for(int i = 1;i <= n; i++)
        s *= i;
    return s;
}
int main()
{
    int a,b;
    scanf("%d%d",&a,&b);
    printf("%I64d\n",zu(a)/(zu(a-b)*zu(b)));
    return 0;
}

在VC6、DEV、CodeBlocks中C语言都可以使用__int64,格式化输出标识为%I64d。__int64是windows专用的,被vc、gcc等编译器支持,在UNIX、Linux中需用long long配合%lld。(标准C的规定。)

#include<stdio.h>
long long zu(int n)
{
    long long s = 1;
    for(int i = 1;i <= n; i++)
        s *= i;
    return s;
}
int main()
{
    int a,b;
    scanf("%d%d",&a,&b);
    printf("%lld\n",zu(a)/(zu(a-b)*zu(b)));  //即使最终答案在所选择的数据类型范围之中,结果依旧有可能溢出
    //输入 21 1 结果为-1
    return 0;
}
前两个都是
答案在所选择的数据类型范围之中,结果依旧有可能溢出
正确程序:

#include<stdio.h>
long long zu(int n,int m)
{
    if(m < n - m) m = n - m;    //小技巧,c(x,y) = c(x,x-y),可以减少s的乘运算
    long long s = 1;
    for(int i = m+1;i <= n; i++)
        s *= i;
    for(int i = 1;i <= n-m; i++)
        s /= i;
    return s;
}
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    printf("%I64d\n",zu(n,m));   //输入21 1 输出21,正确。
    return 0;
}


<think>好的,用户想了解__int128和long long int的区别。首先,我需要确认自己对这两个数据类型的理解是否正确。 首先,long long int是C/C++中的标准整数类型,通常占64位,范围从-2^63到2^63-1。而__int128是GCC扩展提供的128位整数类型,范围更大,但并不是标准的一部分,只能在支持GCC的编译器中使用。 接下来,我应该分几个方面来比较它们。首先是存储大小和范围,然后是编译器支持,接着是使用场景,可能还要提到输入输出的处理方式,以及运算效率的问题。 在存储和范围方面,long long64位,而__int128是128位,所以后者能表示的数值大很多。不过用户需要注意,不是所有编译器都支持__int128,比如MSVC可能不支持,而GCC和Clang支持。 使用场景的话,long long适用于需要大整数但不需要超过64位的情况,而__int128用于需要极大整数的计算,比如大数运算或加密算法,但要注意可移植性,因为它是非标准的。 另外,处理输入输出时,__int128可能需要自己写函数来转换,因为标准库函数如printf不支持直接输出__int128的值。这时候用户需要自己实现将128位数转换为字符串的方法。 运算效率方面,128位的运算可能比64位慢,尤其是在没有硬件支持的平台上,可能会用软件模拟,影响性能。这点在高性能计算中需要注意。 用户可能想知道在什么情况下应该使用哪种类型,所以需要强调如果不需要超过64位的范围,优先使用long long,因为兼容性更好。只有在确实需要处理非常大的数,并且环境支持时,才考虑__int128。 另外,可能用户对如何检测编译器是否支持__int128有疑问,可以提到通过预处理器指令来判断,比如#ifdef __SIZEOF_INT128__。 最后,是否还有遗漏的点?比如,__int128通常是有符号的,而可能有unsigned __int128的存在,但这也取决于编译器支持。同时,C++标准库中的类型如int64_t是对应long long的,而128位类型没有标准定义。 总结下来,需要分点说明两者的区别,并给出使用建议,确保用户能清楚了解各自的优缺点和适用场景。</think>__int128 和 long long int 的区别主要体现在以下几个方面: --- ### 1. **存储空间范围** | 类型 | 位数 | 范围(有符号) | |----------------|--------|------------------------------------------------------------------------------| | `long long int` | 64位 | -9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807 (-2^63 ~ 2^63-1) | | `__int128` | 128位 | -170,141,183,460,469,231,731,687,303,715,884,105,728 ~ <br>170,141,183,460,469,231,731,687,303,715,884,105,727 (-2^127 ~ 2^127-1) | --- ### 2. **编译器支持** - **`long long int`** 是C/C++标准(C99/C++11及更高版本)中定义的标准类型,所有现代编译器均支持(如GCC、Clang、MSVC等)。 - **`__int128`** 是GCC/Clang的扩展类型,**非标准**,仅在部分编译器(如GCC、Clang)中支持,MSVC不支持。 --- ### 3. **典型使用场景** - **`long long int`** 适用于需要较大整数但不超过64位的场景(如时间戳、大数计算等),兼容性强。 - **`__int128`** 适用于需要超大规模整数计算的场景(如加密算法、高精度数值模拟),但需注意代码可移植性。 --- ### 4. **输入输出限制** - **`long long int`** 可直接使用`%lld`或`%llu`格式化输入输出: ```cpp long long x; scanf("%lld", &x); printf("%lld", x); ``` - **`__int128`** 无标准库的格式化支持,需手动转换为字符串或分段处理: ```cpp void print(__int128 x) { if (x < 0) putchar('-'), x = -x; if (x > 9) print(x / 10); putchar(x % 10 + '0'); } ``` --- ### 5. **运算效率** - **硬件支持**:`long long int`的64位运算通常有硬件直接支持,速度更快。 - **软件模拟**:`__int128`的128位运算可能依赖软件模拟(尤其是32位平台),性能较低。 --- ### 6. **代码示例对比** ```cpp // long long int 示例 long long a = 1e18, b = 1e18; long long sum = a + b; // 正确计算 // __int128 示例(仅限GCC/Clang) __int128 x = (__int128)1e36, y = (__int128)1e36; __int128 z = x + y; // 正确存储更大数值 ``` --- ### **总结建议** - 优先使用 `long long int`,除非需要超过64位的整数。 - 若使用 `__int128`,需确保代码仅在支持它的编译器中运行,并自行处理输入输出。 - 对于需要跨平台兼容的代码,避免使用 `__int128`。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值