C/C++中的任意大小整数

8

问题

  • 有没有一种方法可以使用C/C++创建任意大小的整数?

例如:

int main(void) {
  Int i = Int(3); //3-bit integer
  i = 1; //Represented as: 001
}

奖金

  • 有没有一种方法可以处理浮点数?

1
你可以编写一个类来实现这个功能。 - user253751
2
不是作为单独的变量,而是作为结构体或类的一部分:位域。位域 - Mark Ransom
1
如果您尝试在任意大小的浮点数类中执行 1/3 操作,将会导致堆栈溢出! - MSalters
1
如果您想节省内存(位打包会带来一些性能损失),可以在此处查看小任意大小整数:https://dev59.com/WGgt5IYBdhLWcg3wygab#27592777。对于大于标准类型的数据,最好使用某些库。 - dtech
2
FYI,有一个C23提案(http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2709.pdf "Adding a Fundamental Type for N-bit integers")建议通过_BitInt(3)添加它们。如果被批准,这可能是一个额外的未来答案。 - Dwayne Robinson
显示剩余3条评论
5个回答

9

您不能创建比char更小的整数(也就是说,每个对象的大小以sizeof(char)的倍数来衡量,它的值为1)。但这不是问题,因为您可以将数字打包到较大的数字中。

const unsigned size_in_bits = 3;
unsigned a = 1; // 001
unsigned b = 5; // 101
unsigned packed = (b << size_in_bits*1) | (a << size_in_bits*0); // 101001
unsigned unpacked_a = (packed >> size_in_bits*0) & ((1 << size_in_bits)-1);
unsigned unpacked_b = (packed >> size_in_bits*1) & ((1 << size_in_bits)-1);

或者使用位域(语法更好,但二进制布局是实现定义的)。
struct Date
{
    unsigned day : 5;
    unsigned month : 4;
    unsigned year : 21; 
};

Date d;
d.day = 5; d.month = 11; d.year = 2014;

请问您能否详细说明“二进制布局是实现定义”的含义? - Simón Oroño
@SimonOroño - 不能保证不同的编译器会产生相同的布局。标准为了与已经消失的异国平台兼容而将其“非规范化”。如果您想要可移植性,最好按照我在上面评论中链接的问题所描述的编写自己的“手动位域”。 - dtech

5

1
我能用gmp创建一个固定大小的整数吗?根据我的了解,这将创建类似于Python的整数,只要有足够的内存,它们就会增长。 - Simón Oroño
@SimonOroño:至少对于浮点数支持,看起来你需要指定要使用的位数:http://www.mpfr.org/sample.html - Ben Voigt
1
答案缺少“小于一个字节”的方面。 - milleniumbug
@SimonOroño 哦,我没意识到子字节大小对你很重要。 - Aasmund Eldhuset
如果您需要固定宽度整数/浮点数类型,则应使用ttmathboost::multiprecision - phuclv

2
你可以编写一个包装类来封装std::bitset或std::vector。这些都是位容器。
你的类将包含一个容器,并添加转换为和从整数数字的功能,以及其他算术操作。
这将允许您拥有不寻常的位大小整数,如3、5和13。
大多数实现会向最近的8倍数或处理器字长四舍五入。一个3位元素的容器将使用一个带有5个未使用位的uint8_t类型,主要是因为它更容易被处理器操作。一个13位元素的整数将驻留在一个16位元素的程序包中。
编辑1:浮点数 除非你遵循标准的浮点格式,否则你将不得不编写自己的包装类。这将允许你拥有3位的尾数、5位的指数和一位符号——9位。同样,请考虑您需要编写的所有方法。大多数应用程序将使用double或float,因为没有必要编写单独的包装器,这需要编程时间和测试时间。

使用 bitsetvector<bool> 进行环绕操作会使程序变得不必要的缓慢和复杂。bitset 甚至不支持动态大小,必须在编译时确定。 - dtech
自定义位大小的变量由于位集、清除、提取和打包会变得毫无意义、缓慢和复杂。使用 bitsetvector<bool> 作为容器更加便捷。 - Thomas Matthews
根据需求,您可以使用比基于单个位更高效的容器。 - dtech
为什么位容器会更慢?有什么更有效的方法吗?@ddriver - Simón Oroño
@SimonOroño - 因为每个位都有访问开销。对于一个3位整数,您将进行3次位访问,而如果将它们存储在8、16、32或64位整数中,则可以通过一次操作获得3位整数。对于大于64位的整数,位容器的开销将更加明显,使用标准基本整数表示数字将更加高效,并且完全避免了位访问所需的所有掩码和移位。考虑一个128位整数-与128个1位操作相比,这只是两个64位操作。 - dtech
1
具有讽刺意味的是,在现代硬件上,64位整数操作通常只需要一个时钟周期,而位访问仅需要2-3个周期进行访问,您仍然需要进行实际操作。计算机至少可以寻址一个字节,因此,低于字节的操作总是需要进行位运算以提取值的开销。 - dtech

1
解释:


你可以尝试使用数组进行整数和浮点数操作。如果数字太大无法进行数组初始化,你可以使用malloc();函数。
请注意:这种方法不是很快,因为我们将在堆中分配内存。你还需要编写自己的数学运算函数,因为我不太确定如何高效地实现它。 更多内容请见下文。
如何实现(类似):
#include <stdio.h>
#include <stdlib.h>

#define MAX_DIGIT_COUNT 1000

int main()
{
    int* big_num = (int*)malloc(sizeof(int) * MAX_DIGIT_COUNT); //allocate memory
    for(int x; x<MAX_DIGIT_COUNT; x++)
    {
        /*
        *Iterating through number - iterating works, because we are basing out max number lenght 
        *off of the maximum digits, and therefore, we can have a maximum of 2^64 digits
        */
        big_num[x] = rand()%5; //fill up memory block with psuedo-random numbers
    }
    /*Printing begins here...*/
    for(int i; i<MAX_DIGIT_COUNT; i++)
    {
        int iterated;
        iterated = big_num[i];
        printf("%d", iterated);
    }
    printf("\n");
    /*Printing ends here*/
    return 0;
}

请注意:这只是在纯C中实现任意大小数字支持的一种简单粗糙的方法。


顺便说一下,你可以使用“字符数组”来提高内存效率... - user9111069

-2
不,每个基本数据类型(int,short,long等)的大小取决于硬件架构。
如果需要更大的数据类型,您应该使用一个大整数库(它们使用字符串表示数字)。

你能详细说明一下“字符串”是什么意思吗? - Neil Kirk
字符串可以有任意大小,因此您可以拥有更大的数字。 - amchacon
1
问题是重新定义算术运算。@NeilKirk - amchacon
为什么不用一定大小的int数组来表示任意整数呢?这比使用文本字符串要快得多。 - Neil Kirk
1
不,每个原始元素(int、short、long等)的大小取决于硬件架构。嗯——在相同的硬件平台上,我可以使用各种编译器和选项设置,并控制char(有符号或无符号)、int(16位或32位)、long(32位或64位)的范围。我认为编译器具有最终控制权,而不是硬件。 - chux - Reinstate Monica

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接