128bit 整数运算的实现
对于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 整数运算的实现的更多相关文章
- 廖雪峰Java1-2Java程序基础-3整数运算
1.四则运算规则 int i =(100 + 200) * (99 -88);//3300 int n = i + 9;//3309 //除法结果为整数 int q = n / 100;//33 // ...
- linux系统中的命令替换与整数运算$(),$(())
一.$()与`` 在 bash shell 中,$( ) 与 ` ` (反引号) 都是用来做命令替换(command substitution)用的. 所谓的命令替换与我们第五章学过的变量替换差不多, ...
- 用WebService实现两个整数运算
最近,项目开发中需要用到Web Service.自己在网上搜集资料.自己做了一个小例子,用来加深自己对Web Service理解. 概念:Web Service主要是为了使原来各孤立的站点之间的信息能 ...
- 九度OJ 1037:Powerful Calculator(强大的计算器) (大整数运算)
时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:1821 解决:528 题目描述: Today, facing the rapid development of business, SJTU ...
- Java之整数运算
Java的整数运算遵循四则运算规则,可以使用任意嵌套的小括号.四则运算规则和初等数学一致.例如: public class Main { public static void main(String[ ...
- shell中命令代换$()与`` 、 变量代换${} 、 整数运算$(( )) 的区别
命令代换$()与`` . 变量代换${} . 整数运算$(( )) 1.$( ) 与 ` ` (反引号) 在 bash shell 中,$( ) 与 ` ` (反引号) 都是用来做命令替换用(comm ...
- 【Weiss】【第03章】练习3.9:大整数运算包
[练习3.9] 编写任意精度的整数运算包,要求使用类似多项式运算的方法.计算24000内数字0到9的分布.
- 《深入Java虚拟机学习笔记》- 第12章 整数运算
Java虚拟机提供几种进行整数算术运算的操作码,他们执行基于int和long类型的运算.当byte.short和char类型值参与算术运算时,首先会将它们转换为int类型.这些操作码都不会抛出异常,溢 ...
- C语言课程设计大整数运算
该大整数运算系统用于对有符号的位数不超过500位的大整数进行加.减.乘.除四则运算和计算N(0<=N<=10000)的阶乘.注意事项 : 1.操作期间,进行四则运算时若大整数为正数请 ...
随机推荐
- 找到排序矩阵中从小到大第K个数字
一 题目描述 在一个排序矩阵中找从小到大的第 k 个整数. 排序矩阵的定义为:每一行递增,每一列也递增. 二 题解 由于排序矩阵中的每一行都是递增的,并且每一列都是递增的.从小到大第k个数,实际上就是 ...
- 20164310Exp6 信息搜索和漏洞扫描
实践内容 (1)各种搜索技巧的应用 (2)DNS IP注册信息的查询 (3)基本的扫描技术:主机发现.端口扫描.OS及服务版本探测.具体服务的查点(以自己主机为目标) (4)漏洞扫描:会扫,会看报告, ...
- [css选择器]总结:IE6不支持的CSS选择符
转载地址:https://www.wenjiwu.com/doc/zvsbii.html.此文最后也给出了原文地址,但是我点击过去发现是什么赌博彩票的地址,360也弹出小心的提示,所以这里只给出了我转 ...
- ubuntu16.04上vue环境搭建
$ sudo apt-get install python-software-properties $ curl -sL https://deb.nodesource.com/setup_8.x | ...
- centos7 系统优化脚本
脚本一: #!/usr/bin/env bash #设置环境变量 export PATH=$PATH:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sb ...
- 文件数据缓存(key-Value)
为了解决大量数据缓存,消耗内存过多的问题,特别实现了文件缓存:该缓存主要是应用于多存少读的情况,一般我们做缓存是实现将数据放在内存中或者数据库中:放在内存中就会消耗很大内存,尤其在高并发大数据缓存时, ...
- DocKer 创建容器 镜像端口映射失败
问题一: 我想使用同一个镜像创建多个容器,并映射端口出现以下错误,该怎么解决? docker: Error response from daemon: driver failed programmin ...
- DLC 基本定律与规则
字母数字码 :除了数字以外,数字系统还需要处理数字以外的符号,如标点符号,控制命令等 最常见的是ASCII ASCII码是7位二进制码有128种组合,表示128个符号例如 二进制表示 十六进制表示 十 ...
- C 语言 保留的关键字
auto,break,case,char,const,continue, default,do,double,else,enum,extern, float,for,goto,if,int,long, ...
- JavaScript代理模式
代理模式的定义,代理是一个对象(proxy)用它来控制目标对象的访问.为此他要是先与目标对象相同的接口,但是他不同于装饰者模式,它对目标对象不进行任何修改,它的目的在于延缓"复杂" ...