背景:

计算机是以一串二进制数,用约定的表示方式来存储数据的。约定表示方式的不同,造成了可以表示数的范围不同。其中,对于整数类型数据的表示,有unsigned integer(无符号整型)和signed integer(有符号整型)两种方式。其中,无符号整型是所有二进制数都用来表示数值,仅能表示非负整数。故,对于一串长度为N的无符号二进制数,可以表示 0~2N-1之间的整数;

而有符号整型的是第一位二进制数表示数值的正负,后面剩余的位数表示数值。对于一串长度为N的有符号二进制数,可以表示 -2N-1~2N-1-1之间的整数。

比如,对于 1字节(8位)的二进制数,用无符号整型可以表示0~255范围(0~28-1)的整数,用有符号整型可以表示-128~+127范围(-27~27-1)的整数。对于一个8位二进制数,不同的表示方式可能解析出不同的数值:

数值(二进制)

无符号整型

unsigned integer

所有位都用来表示大小

有符号整型

signed intger(kind=1)

第一位表示符号正负。

如果为负数,其数值为补码(按位取反加一)的值

11111111

会被识别成255

会被识别成 -1

第一位为1,表示值为负,其数值为补码:(00000001)

01000000 64

+64

第一位为0,表示值为正,其数值为原码:(01000000)

10000000 128

会被识别成 -128

第一位为1,表示值为负,其数值为补码:(10000000)

10000001

129

会被识别成 -127

第一位为1,表示值为负,其数值为补码:(01111111)

高位补零,扩展精度,实现读取无符号整型数据:

由于Fortran不支持无符号整型(unsigned integer)。对这种以无符号整型方式存储的数据,如果仍然使用有符号整型的方式读取,可能会出现结果的错误。

比如,对于一个以2字节(16位)无符号整型方式存储的整数32769,其二进制表示为(1000 0000 0000 0001),超过了2字节有符号整型的表示范围 -32768~32767 ( -216-1~216-1-1)。这时候,如果仍然以有符号短整型变量的格式读取上述数据,则会错误地其识别成-32767(第一位为1,则计算机认为这个数为负数。对这个数的剩余位取补码,得到值32767(即01111 1111 1111 1111),所以这个数被识别成了-32767)。

一个解决办法是,更高长度的有符号整型数表示对于读取的数据,可以将其高位补0(使用zext函数(gfortran编译器不支持)),扩展成更高精度的有符号整数。

在本例子中,如下:

program testimplicit none!// b'1000000000000001' !//待写入的二进制数。长度16位,十进制值为32769integer(kind=2) :: xint1 !// 短整型integer(kind=4) :: xint4 !// 整型
!//待写入文件的二进制数。十进制值为32769write(*,*)"xint0 :", b'1000000000000001'
!//写二进制数到文件!//access="stream"必须添加,否则就会以Fortrans顺序存储的方式存储文件。参见https://www.cnblogs.com/jiangleads/p/9022051.html!//status="replace"必须添加,否则可能出现新保存的文件大小和理论大小不一致。!//经过试验,Fortran最小的输出单元是4个字节,如果要输出的数据/变量不到4个字节,则剩余位数都会补零。open(11,file="test.bin",access="stream",form="unformatted",action="write",status="replace")write(11)b'1000000000000001'close(11)
!//从文件读二进制数。Fortran只能以有符号的形式读取到整数open(11,file="test.bin",access="stream",form="unformatted",action="read")read(11)xint1close(11)
!//以有符号形式读取到的数。将其识别成了(-32767)write(*,*)"xint(kind=2) before zext:", xint1
!//对数字的高位补零,扩展到16位(4字节)整型xint4 = zext(xint1,4)
!//输出到正确的结果(32769)write(*,*)"xint(kind=4) after zext:",xint4
end program

输出为


xint0 : 32769
xint(kind=2) before zext: -32767
xint(kind=4) after zext: 32769
Press any key to continue . . .

另注:经过试验,Fortran最小的输出单元是4个字节,如果要输出的数据/变量不到4个字节,则剩余位数都会补零。

利用截断+逻辑运算,转换无符号整型数据(无需扩展精度):

以下为 利用截断+逻辑运算的方法 处理无符号整数的方法。 优点是 不改变数据存储空间的大小, 缺点是不能对转换后的变量进行运算。

参考网址 UNSIGNED INTEGERS - Intel Communities (https://community.intel.com/t5/Intel-Fortran-Compiler/UNSIGNED-INTEGERS/m-p/876899)

一些数据是以无符号整数处理的,而标准的Fortran不支持这种类型的数据定义。尽管一些厂商的Fortran (Sun g95)支持定义unsigned定义无符号整型数,但这个方法并不受到Fortran社区推荐。

在许多情况下,可以使用INTEGER(C_INT)进行替代,其中C_INT是内部模块ISO_C_BINDING(10.0及更高版本)中定义的常量,但不要尝试直接使用它进行无符号运算。通常可以得到所需的结果,但有时需要将无符号数通过ZXET函数(0扩展函数,将输入二进制数的左边(高位)补0)转换为INTEGER(8),然后将其截断为INTEGR(C_INT)。 (注:截断方法,使用IBITS函数)

比如

integer(kind=4) :: ui4bytes!//4字节无符号整型数
integer(kind=8) :: i8bytes !//8字节有符号整型数
integer(kind=4) :: i4bytes !//4字节有符号整型数 !//利用zext函数,将4字节无符号整型数,高位补零,扩展到8字节,结果输出到i8bytes
i8bytes = zext(ui4bytes,8) !//利用ibits函数,将8字节有符号整数,截断选取前4个字节(即从第0位开始,截取32位),结果存储到i4bytes
i4bytes = ibits(i8bytes,0,32)

!//注意:由于截断,原先超出范围的数据无法正常显示

截断+逻辑运算进行转换的例子:处理使用unsigned integer 整型 (1个字节):

假设Fortran数组使用 INTEGER, INTEGER(2), INTEGER(4), 和 INTEGER(8),假设数据的值范围是0:255

一个较为直接的办法是,使用INT函数,将较大的数转换到Integer(1)中:

INTEGER :: in(n)
INTEGER(1) :: out(n) do i=1,n
out(i) = INT(in(i),1) !//即,将其转换成1字节大小的整数
end do

转换回来的方法,进行逻辑与运算IAND

INTEGER(1) :: in(n)
INTEGER :: out(n) do i=1,n
out(i) = IAND(INT(in(i)),255)
end do

注: 函数IBITS用法

IBITS函数的作用为:截取指定位范围内的位(二进制)序列。用法为RESULT = IBITS(I, POS, LEN)

IBITS从I中提取长度为LEN的字段,从右边往左数(对于字节序为小端Little Endian而言)的第POS位开始(最右边是第0位),向左延伸LEN位。结果右对齐,其余位归零。POS+LEN的值必须小于或等于值BIT_SIZE(I)。

例子1: IBITS(12,1,4) 结果是6

上式意思为,对12这个数,取其二进制的第1位,截取长度为4的数据,返回结果。

说明:对于占4个字节的整型数据,12这个数的二进制为 0000 0000 0000 1100,二进制的第1位,也就是从右往左数的第2个位置(因为最右边是第0位),值是0,截取长度为4的数据,就是‘0110’,然后右对齐,剩余位补充0,结果就是二进制的0000 0000 0000 0110,换算成10进制就是6

例子2: IBITS(10,1,7)的结果是5

10,其二进制为0000 0000 0000 1010,从右边第1位开始值第7位的数是’0000101‘,右对齐,空位补0之后,就是二进制的0000 0000 0000 0101,换算成10进制就是5。

后记:

另外,据Fortran语言论坛介绍1,2,Fortran2008标准中推出了BITS这个类型,但是目前的编译器似乎不支持这个语法规范,若想实现BITS类型,需要自行编译这个库https://github.com/fortran-lang/stdlib

1. https://fortran-lang.discourse.group/t/module-for-dealing-with-unsigned-integers-in-standard-fortran/1242

2. https://fortran-lang.discourse.group/t/unsigned-integer-data-type-in-modern-fortran/1285

3. https://stevelionel.com/drfortran/2020/08/11/doctor-fortran-in-were-all-bozos-on-this-bus

Fortran处理无符号整型unsigned integer的更多相关文章

  1. 无符号整型 unsigned int、unsigned long、usigned long long、size_t 比较和格式控制

    位数比较 由于数据的长度和平台相关,所以基于 64 位系统比较. Windows Linux unsigned int 32 bits/4294967295 32 bits unsigned long ...

  2. 整型,长整型,无符号整型等 大端和小端(Big endian and Little endian)

    一.大端和小端的问题 对于整型.长整型.无符号整型等数据类型,Big endian 认为第一个字节是最高位字节(按照从低地址到高地址的顺序存放数据的高位字节到低位字节):而 Little endian ...

  3. CoreSeek有符号整型

    数据库status字段的值有:-1,0,1 设置过滤字段,发现sql_attr_uint不支持负数,后改用sql_attr_bigint sql_attr_bigint = status sql_at ...

  4. C语言之将无符号字符型转化为ascii码值

    这个宏是在linux内核中获取的,主要的功能是能够将一个无符号字符型的参数转化为ASCII码值. ASCII : ASCII 编码里包括了128个字符.用 十进制 0  到 127 来表示 .那就对了 ...

  5. C++ 无符号整型和整型的区别

    在Win 7系统中,short 表示的范围为 - 32767到 32767,而无符号的short表示的范围为0 到 65535,其他类型的同理可推导出来,当然,仅当数字不为负的时候才使用无符号类型. ...

  6. v.size() return size_t not int 返回无符号整型数

    In the C++ STL, the vector size() function return size_t, which is unsigned int, not int. So imagine ...

  7. 关于整型Integer、Int32、Int64、IntPtr、UINT、UInt32、Cardinal、UInt64、UIntPtr、NativeUInt、Pointer、Handle

    知识点1:UIntPtr = NativeUInt = Pointer = Handle 随程序的位数改变而改变.如下: 所以以后再用指针的时候要这样:UintPtr/NativeUInt(实例) = ...

  8. C语言的整型溢出问题

    整型溢出有点老生常谈了,bla, bla, bla… 但似乎没有引起多少人的重视.整型溢出会有可能导致缓冲区溢出,缓冲区溢出会导致各种黑客攻击,比如最近OpenSSL的heartbleed事件,就是一 ...

  9. 【CSAPP笔记】2. 整型运算

    现在想补补推荐这本书的理由. Most books on systems-computer architecture, compilers, operating systems, and networ ...

  10. [C]基本数据类型:整型(int)用法详解

    1.整型int C语言提供了很多整数类型(整型),这些整型的区别在于它们的取值范围的大小,以及是否可以为负.int是整型之一,一般被称为整型.以后,在不产生歧义的情况下,我们把整数类型和int都称为整 ...

随机推荐

  1. mysql8.0.30主从配置

    安装包下载地址: https://downloads.mysql.com/archives/community/ 1. 解压介质包: # tar xf mysql-8.0.30-linux-glibc ...

  2. 2020icpc沈阳H

    优化转移DP Problem - H - Codeforces 题意 Aloha 要骑单车,可以单独花费 \(r\) 元骑 1 次,也可以购买某一种单车卡,第 \(i\) 种单车卡 \(c_i\) 元 ...

  3. UE4笔记索引

    图形 渲染 延迟渲染 三维渲染流程 渲染优化 基本渲染 材质 材质节点组合 节点分类 特别的属性 其他 坐标空间与切线空间 坐标轴 编码 平台相关 UBT编译 命令行 程序到CPU路径 C++与蓝图互 ...

  4. el-table多选框根据条件隐藏显示

    提供一个方法, 通过添加相应类来控制样式,设置 display: none ,达到隐藏 checkbox 的目的. 利用Table Attributes 属性里面的 cell-class-name 属 ...

  5. 解决多行文本超出显示省略号webpack打包后失效的问题

    开发环境没问题: 但是在打包部署后就失效了: 经过对比后发现是因为: 缺少了 -webkit-box-orient: vertical;  导致 解决方案 : /* ! autoprefixer: o ...

  6. JMeter压力测试之环境搭建、脚本调试及报错解决方法(Linux版)

    一.环境部署 后续往服务器上传文件,本文中使用的是xftp,因其不是本文所要讲述的重点,这里不做详解. 第一步:安装所需要版本的JDK,本次使用的是JDK 1.8 下载地址:http://www.or ...

  7. js中的加法运算

  8. python 对接各大数据库,快速上手!

      1.mysql 安装pymysql pip intsall pymysql 快速上手 import pymysql # 第一步:连接到数据库 con = pymysql.connect(host= ...

  9. 用Nodemailer发个邮件不算难?

    公司一直用邮箱做一些部门间协调的沟通留存,于是乎想用点"编程思维"做些"工作流"来自动化处理:但是公司用的邮箱有点难登呐! 选用的Nodejs 作为实现语言,那 ...

  10. cocos2d-lua 控制台输入Lua指令方便调试

    用脚本进行开发,如果不能实时去输入指令,就丧失了脚本的一大特色,所以对cocos2d-x程序稍微修改下,使其可以直接从控制台读入lua指令,方便调试. 1 首先在行首加入lua的引用,如下 1 #in ...