对于128bit的长整型运算,GCC提供了扩展类型:__int128。然而该类型不在C/C++语言的标准之中,并且对于不同种类的编译器,它的实现情况不同。因此,在编写相关的可移植程序时,我们有必要实现__int128兼容层。

  以下给出一种比较高效的C语言实现,该代码出自QEMU-2.8源码树。该方案采用了拼接两个64bit整数的方法。目前较常见的方法是模拟进制运算(多见于类ACM题目)。模拟运算的优点在于逻辑直观,可处理的位数不受限制,但大于128bit的精度在工程运用中已经很少可见,加上其较大的空间和时间开销,因此几乎不被采用。位数拼接的方法在性能上更胜一筹。值得一提的是,源代码对加法进位的处理非常巧妙。其实现思路在注释中已经清晰地给出了,本文不再重复。

  约定,在编译程序前,自动化工具会对编译器是否支持__int128进行检查,如果支持,则定义CONFIG_INT128宏,使得兼容层完全采用原生运算符操作。由于采用内联函数,此时兼容层面的开销为0。

  如果编译器不支持__int128,则兼容层将采用两个64bit整数拼接的方法,完成__int128的运算。

  本兼容层支持加法、累加、比较和位运算。

#ifndef INT128_H
#define INT128_H

#ifdef CONFIG_INT128

typedef __int128_t Int128;

static inline Int128 int128_make64(uint64_t a)
{
    return a;
}

static inline Int128 int128_make128(uint64_t lo, uint64_t hi)
{
     | lo;
}

static inline uint64_t int128_get64(Int128 a)
{
    uint64_t r = a;
    assert(r == a);
    return r;
}

static inline uint64_t int128_getlo(Int128 a)
{
    return a;
}

static inline int64_t int128_gethi(Int128 a)
{
    ;
}

static inline Int128 int128_zero(void)
{
    ;
}

static inline Int128 int128_one(void)
{
    ;
}

static inline Int128 int128_2_64(void)
{
     << ;
}

static inline Int128 int128_exts64(int64_t a)
{
    return a;
}

static inline Int128 int128_and(Int128 a, Int128 b)
{
    return a & b;
}

static inline Int128 int128_rshift(Int128 a, int n)
{
    return a >> n;
}

static inline Int128 int128_add(Int128 a, Int128 b)
{
    return a + b;
}

static inline Int128 int128_neg(Int128 a)
{
    return -a;
}

static inline Int128 int128_sub(Int128 a, Int128 b)
{
    return a - b;
}

static inline bool int128_nonneg(Int128 a)
{
    ;
}

static inline bool int128_eq(Int128 a, Int128 b)
{
    return a == b;
}

static inline bool int128_ne(Int128 a, Int128 b)
{
    return a != b;
}

static inline bool int128_ge(Int128 a, Int128 b)
{
    return a >= b;
}

static inline bool int128_lt(Int128 a, Int128 b)
{
    return a < b;
}

static inline bool int128_le(Int128 a, Int128 b)
{
    return a <= b;
}

static inline bool int128_gt(Int128 a, Int128 b)
{
    return a > b;
}

static inline bool int128_nz(Int128 a)
{
    ;
}

static inline Int128 int128_min(Int128 a, Int128 b)
{
    return a < b ? a : b;
}

static inline Int128 int128_max(Int128 a, Int128 b)
{
    return a > b ? a : b;
}

static inline void int128_addto(Int128 *a, Int128 b)
{
    *a += b;
}

static inline void int128_subfrom(Int128 *a, Int128 b)
{
    *a -= b;
}

#else /* !CONFIG_INT128 */

typedef struct Int128 Int128;

struct Int128 {
    uint64_t lo;
    int64_t hi;
};

static inline Int128 int128_make64(uint64_t a)
{
     };
}

static inline Int128 int128_make128(uint64_t lo, uint64_t hi)
{
    return (Int128) { lo, hi };
}

static inline uint64_t int128_get64(Int128 a)
{
    assert(!a.hi);
    return a.lo;
}

static inline uint64_t int128_getlo(Int128 a)
{
    return a.lo;
}

static inline int64_t int128_gethi(Int128 a)
{
    return a.hi;
}

static inline Int128 int128_zero(void)
{
    );
}

static inline Int128 int128_one(void)
{
    );
}

static inline Int128 int128_2_64(void)
{
    ,  };
}

static inline Int128 int128_exts64(int64_t a)
{
    ) ? - :  };
}

static inline Int128 int128_and(Int128 a, Int128 b)
{
    return (Int128) { a.lo & b.lo, a.hi & b.hi };
}

static inline Int128 int128_rshift(Int128 a, int n)
{
    int64_t h;
    if (!n) {
        return a;
    }
    h = a.hi >> (n & );
    ) {
        );
    } else {
         - n)), h);
    }
}

static inline Int128 int128_add(Int128 a, Int128 b)
{
    uint64_t lo = a.lo + b.lo;

    /* a.lo <= a.lo + b.lo < a.lo + k (k is the base, 2^64).  Hence,
     * a.lo + b.lo >= k implies 0 <= lo = a.lo + b.lo - k < a.lo.
     * Similarly, a.lo + b.lo < k implies a.lo <= lo = a.lo + b.lo < k.
     *
     * So the carry is lo < a.lo.
     */
    return int128_make128(lo, (uint64_t)a.hi + b.hi + (lo < a.lo));
}

static inline Int128 int128_neg(Int128 a)
{
    uint64_t lo = -a.lo;
    return int128_make128(lo, ~(uint64_t)a.hi + !lo);
}

static inline Int128 int128_sub(Int128 a, Int128 b)
{
    return int128_make128(a.lo - b.lo, (uint64_t)a.hi - b.hi - (a.lo < b.lo));
}

static inline bool int128_nonneg(Int128 a)
{
    ;
}

static inline bool int128_eq(Int128 a, Int128 b)
{
    return a.lo == b.lo && a.hi == b.hi;
}

static inline bool int128_ne(Int128 a, Int128 b)
{
    return !int128_eq(a, b);
}

static inline bool int128_ge(Int128 a, Int128 b)
{
    return a.hi > b.hi || (a.hi == b.hi && a.lo >= b.lo);
}

static inline bool int128_lt(Int128 a, Int128 b)
{
    return !int128_ge(a, b);
}

static inline bool int128_le(Int128 a, Int128 b)
{
    return int128_ge(b, a);
}

static inline bool int128_gt(Int128 a, Int128 b)
{
    return !int128_le(a, b);
}

static inline bool int128_nz(Int128 a)
{
    return a.lo || a.hi;
}

static inline Int128 int128_min(Int128 a, Int128 b)
{
    return int128_le(a, b) ? a : b;
}

static inline Int128 int128_max(Int128 a, Int128 b)
{
    return int128_ge(a, b) ? a : b;
}

static inline void int128_addto(Int128 *a, Int128 b)
{
    *a = int128_add(*a, b);
}

static inline void int128_subfrom(Int128 *a, Int128 b)
{
    *a = int128_sub(*a, b);
}

#endif /* CONFIG_INT128 */
#endif /* INT128_H */

128bit 整数运算的实现的更多相关文章

  1. 廖雪峰Java1-2Java程序基础-3整数运算

    1.四则运算规则 int i =(100 + 200) * (99 -88);//3300 int n = i + 9;//3309 //除法结果为整数 int q = n / 100;//33 // ...

  2. linux系统中的命令替换与整数运算$(),$(())

    一.$()与`` 在 bash shell 中,$( ) 与 ` ` (反引号) 都是用来做命令替换(command substitution)用的. 所谓的命令替换与我们第五章学过的变量替换差不多, ...

  3. 用WebService实现两个整数运算

    最近,项目开发中需要用到Web Service.自己在网上搜集资料.自己做了一个小例子,用来加深自己对Web Service理解. 概念:Web Service主要是为了使原来各孤立的站点之间的信息能 ...

  4. 九度OJ 1037:Powerful Calculator(强大的计算器) (大整数运算)

    时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:1821 解决:528 题目描述: Today, facing the rapid development of business, SJTU ...

  5. Java之整数运算

    Java的整数运算遵循四则运算规则,可以使用任意嵌套的小括号.四则运算规则和初等数学一致.例如: public class Main { public static void main(String[ ...

  6. shell中命令代换$()与`` 、 变量代换${} 、 整数运算$(( )) 的区别

    命令代换$()与`` . 变量代换${} . 整数运算$(( )) 1.$( ) 与 ` ` (反引号) 在 bash shell 中,$( ) 与 ` ` (反引号) 都是用来做命令替换用(comm ...

  7. 【Weiss】【第03章】练习3.9:大整数运算包

    [练习3.9] 编写任意精度的整数运算包,要求使用类似多项式运算的方法.计算24000内数字0到9的分布.

  8. 《深入Java虚拟机学习笔记》- 第12章 整数运算

    Java虚拟机提供几种进行整数算术运算的操作码,他们执行基于int和long类型的运算.当byte.short和char类型值参与算术运算时,首先会将它们转换为int类型.这些操作码都不会抛出异常,溢 ...

  9. C语言课程设计大整数运算

    该大整数运算系统用于对有符号的位数不超过500位的大整数进行加.减.乘.除四则运算和计算N(0<=N<=10000)的阶乘.注意事项 :    1.操作期间,进行四则运算时若大整数为正数请 ...

随机推荐

  1. 前端需要了解的HTTP协议

    目录 HTTP协议 HTTP概述 HTTP之URL HTTP状态码 HTTP首部 HTTP首部字段 HTTP通用首部字段 HTTP请求首部字段 HTTP工作原理 HTTP报文内的HTTP信息 HTTP ...

  2. 树莓派中学TensorFlow

    树莓派中默认的虚拟环境为python 2.x,需要用下面的-p参数修改为python3环境.电信wifi和公司网络直接用pip3 install TensorFlow都不好使,用联通手机热点可以安装. ...

  3. MySQL data type

    MySQL数据类型 MySQL中定义数据字段的类型对你数据库的优化是非常重要的. MySQL支持多种类型,大致可以分为三类:数值.日期/时间和字符串(字符)类型. 数值类型 MySQL支持所有标准SQ ...

  4. promise规范之部分总结

    1. promise构造函数中的reject和resolve是微任务, 即先执行resolve后的代码,再执行之前通过then注册的代码 2. 对于状态已变更的promise来说,比如promiseA ...

  5. Django字符串翻译

    文章出处:https://www.jb51.net/article/70077.htm Django模板使用两种模板标签,且语法格式与Python代码有些许不同. 为了使得模板访问到标签,需要将 {% ...

  6. jumpservice一步一步安装

    一步一步安装 (CentOS) 本文档旨在帮助用户了解各组件之间的关系, 生产环境部署建议参考 进阶安装文档 云服务器快速部署参考 极速安装 安装过程中遇到问题可参考 安装过程中常见的问题 测试推荐环 ...

  7. Pandas中Loc用法总结

    摘自:http://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.loc.html 具体用法,假设数据源为: > ...

  8. C# 控件之数据绑定

    增加一个委托方法,可以实现后台多线程直接更新UI界面的值,利用了控件的DataBindings,以及 INotifyPropertyChanged接口和事件委托机制. 如果只是通过INotifyPro ...

  9. LayaAir疑难杂症之三:1.7版本click()、execCommand('copy')函数不生效

    问题描述 在使用Laya1.7引擎开发H5游戏时,引入Js原生函数click( ),模拟一次点击事件,发现无效.在使用Laya1.7引擎开发H5游戏时,引入Js原生函数execCommand('cop ...

  10. Kettle通过Webservice获取天气信息

      Kettle通过Webservice获取天气信息 需求: 通过kettle工具,通过webservice获取天气信息,写成xml格式文件. 思路: Kettle可通过两种选择获取webservic ...