背景:

计算机是以一串二进制数,用约定的表示方式来存储数据的。约定表示方式的不同,造成了可以表示数的范围不同。其中,对于整数类型数据的表示,有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. net core 添加cors,解决跨域问题

    ConfigureServices //允许跨域 services.AddCors(options => { options.AddPolicy("any", builder ...

  2. OpenAI Java SDK——chatgpt-java-v1.0.3更新支持GPT-3.5-Turbo,支持语音转文字,语音翻译。

    简介 chatgpt-java是一个OpenAI的Java版SDK,支持开箱即用.目前以支持官网全部Api.支持最新版本GPT-3.5-Turbo模型以及whisper-1模型.增加chat聊天对话以 ...

  3. Vue2安装less版本过高问题,需要降级

    安装指定less版本解决: -D: 本地安装 -g: 全局安装 npm install less@3.9.0 less-loader@5.0.0 -D

  4. EF Core自动将实体映射到数据库

    protected override void OnModelCreating(ModelBuilder modelBuilder) { try { var compilationLibrary = ...

  5. c++多线程thread用法小例子

    测试分布式存储系统时,针对并发测试,同时创建500个文件,采用这种方法. #include<iostream> #include<thread> using namespace ...

  6. drf从入门到飞升仙界 08

    断点调试使用 # 程序在debug模式运行,可以在任意位置停下,查看当前情况下变量数据的变化情况 # 使用pycharm调试程序 - 1.以debug模式运行. - 2.在代码左侧加入断点(红圈) - ...

  7. css3的的新特性

    1.transform 2.calc 3.transition

  8. 225-基于XCVU440T的多核处理器多输入芯片验证板卡

    225-基于XCVU440T的多核处理器多输入芯片验证板卡   基于XCVU440T的多核处理器多输入芯片验证板卡 一.板卡概述 本板卡系我司自主研发的基于6U CPCI处理板,适用于多核处理器多输入 ...

  9. 右键无法新建word文件怎么办?

      电脑用久了,总会出现奇奇怪怪的问题.   我最近遇到一个问题:鼠标右键无法新建word文件.如何解决此问题呢?   刚开始,我忍了.解决方法为:把word图标固定到任务栏,就好了呗,需要用的时候, ...

  10. Launchpad是什么?Launchpad使用教程

    ​ Launchpad是什么?Launchpad 是用来查找和打开Mac系统下的 app 的最快捷方式,通过 Launchpad,您可以查看.整理并轻松打开Mac里面几乎所有的应用软件.下面带来Mac ...