GMP库中的mpz_t转换为无符号长整型(unsigned long long)

7

在C语言中,有没有一种方法将mpz_t变量转换为unsigned long long?反过来呢,从ull转换为mpz_t?由于ull是C99的一部分,gmp库不支持这个功能。

我找到了这个,但它是用c++编写的,而我不知道如何使用c ++。谢谢提前。


我很惊讶没有提到过mpz_import/mpz_export。 - Marc Glisse
@MarcGlisse 公平地说,我不是一个gmp专家,我只是试图将链接的C++代码直接翻译成C语言。 - C. K. Young
2个回答

8
以下是一些用于在unsigned long long和mpz_t之间进行翻译的函数。请注意,如果数字太大而无法适应unsigned long long,则mpz2ull将破坏您的堆栈:
unsigned long long mpz2ull(mpz_t z)
{
    unsigned long long result = 0;
    mpz_export(&result, 0, -1, sizeof result, 0, 0, z);
    return result;
}

void ull2mpz(mpz_t z, unsigned long long ull)
{
    mpz_import(z, 1, -1, sizeof ull, 0, 0, &ull);
}

非常好,谢谢。我不熟悉strtoull,为什么它的第二个参数设置为0? - kaiseroskilo
@kaiseroskilo:第二个参数需要一个“结束指针”,如果给定了,它将被设置为数字解析的结尾。这样,您可以进行错误检查:如果结尾在空终止符处,则整个字符串是有效的数字。通过传递null(在我的代码中写作0),这意味着我不关心结束指针,因为我盲目相信gmp_snprintf始终会提供有效的输出。;-) - C. K. Young
谢谢。在第二个函数上出现了segfault,可能只需要在mpz_t result;后面加上mpz_init(result)。 - DannyKK
正如 http://stackoverflow.com/questions/18416425/converting-an-ull-to-an-mpz-t 中所指出的,这段代码存在几个问题。snprintf 调用缺少一个参数(n 和 ull 未使用)。你不能返回一个 mpz_t。 - Marc Glisse
@MarcGlisse 感谢您的提醒!我今晚稍后会修复这个问题。 - C. K. Young
@MarcGlisse,正如你所提到的,我已经重新实现了这些函数,使用了mpz_exportmpz_import。(这次我甚至测试过它们!)注意:如果数字太大而无法容纳,则mpz2ull将破坏您的堆栈。这是一种特性(尽管具有未定义的行为,为了保持代码简单),而不是错误。;-) - C. K. Young

4

这些函数应该可以将mpz_t类型和有符号/无符号的long long类型相互转换。它们应该是相当快速的,因为它们避免了字符串处理:

void mpz_set_sll(mpz_t n, long long sll)
{
    mpz_set_si(n, (int)(sll >> 32));     /* n = (int)sll >> 32 */
    mpz_mul_2exp(n, n, 32 );             /* n <<= 32 */
    mpz_add_ui(n, n, (unsigned int)sll); /* n += (unsigned int)sll */
}

void mpz_set_ull(mpz_t n, unsigned long long ull)
{
    mpz_set_ui(n, (unsigned int)(ull >> 32)); /* n = (unsigned int)(ull >> 32) */
    mpz_mul_2exp(n, n, 32);                   /* n <<= 32 */
    mpz_add_ui(n, n, (unsigned int)ull);      /* n += (unsigned int)ull */
}

unsigned long long mpz_get_ull(mpz_t n)
{
    unsigned int lo, hi;
    mpz_t tmp;

    mpz_init( tmp );
    mpz_mod_2exp( tmp, n, 64 );   /* tmp = (lower 64 bits of n) */

    lo = mpz_get_ui( tmp );       /* lo = tmp & 0xffffffff */ 
    mpz_div_2exp( tmp, tmp, 32 ); /* tmp >>= 32 */
    hi = mpz_get_ui( tmp );       /* hi = tmp & 0xffffffff */

    mpz_clear( tmp );

    return (((unsigned long long)hi) << 32) + lo;
}

long long mpz_get_sll(mpz_t n)
{
    return (long long)mpz_get_ull(n); /* just use unsigned version */
}

函数的签名应该像本地 GMP 函数一样。 与其他 gmpz_set_ 函数一样,这些函数假设传递的变量已经初始化,但很容易将它们更改为 gmp_init_set_ 样式的函数。


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