【专业技术】C语言里面丰富多彩的浮点运算

编者按:浮点运算,说起来简单,实现起来可不是那么容易的事情,我们认为很简单的运算,计算机特别是嵌入式处理器实现起来,也不是那么容易。嵌入式处理器,用的最多的当属ARM家族了,我也每天都跟她打交道,但对于软浮点,硬浮点,vfp,softfp,刚开始我也并不清楚怎么用。

下文这篇文章,对arm处理器的浮点讲的很清楚。

很多时候我们要处理的数据,不仅仅是整数和字符串,还有浮点数即小数。在多媒体数据处理方面表现的更多。是不是所有的CPU都支持,浮点运算呢?

答案:不是。

我们常常听到赢浮点和软浮点,这些到底说的是什么呢?下面我们就来一探究竟吧。在这里我们说的是ARM核浮点运算。

(1)硬浮点(hard-float)

编译器将代码直接编译成硬件浮点协处理器(浮点运算单元FPU)能识别的指令,这些指令在执行的时候ARM核直接把它转给协处理器执行。FPU 通常有一套额外的寄存器来完成浮点参数传递和运算。使用实际的硬件浮点运算单元(FPU)会带来性能的提升。

(2)软浮点(soft-float)

编译器把浮点运算转成浮点运算的函数调用和库函数调用,没有FPU的指令调用,也没有浮点寄存器的参数传 递。浮点参数的传递也是通过ARM寄存器或者堆栈完成。现在的Linux系统默认编译选择使用hard-float,如果系统没有任何浮点处理器单元,这 就会产生非法指令和异常。因而一般的系统镜像都采用软浮点以兼容没有VFP的处理器。

用一句话总结,软浮点是通过浮点库去实现浮点运算的,效率低;硬浮点是通过浮点运算单元(FPU)来完成的,效率高。

一、使用浮点库实现浮点运算(soft-float)

例如:我想实现两个浮点数相加,代码如下:

使用GNU ARM编译器翻译成的部分汇编代码如下:

从图中我们可以知道,默认情况下,编译器使用的是软浮点,图中__aeabi_fadd这个函数是在浮点库中实现。如果想让代码能正常的运行,还需要在连接的时候静态连接一下浮点库。

在这里我们以一个完成的案例来说明一下,软浮点库的使用方法。

start.S:

.global _start

#define USER_MODE 0x10

_start:

@设置CPU为user模式

mov r0,#USER_MODE

msr cpsr_c,r0

@跳到main函数

ldr sp,=0x34000

bl main

stop:

b stop

main.c:

int main()

{

float f1,f2,f3;

f1 = 1.24;

f2 = 1.22;

f3 = f1 + f2;

return 0;

}

Makefile:

LD=arm-none-eabi-ld

OBJDUMP=arm-none-eabi-objdump

RM=rm -rf

CFLAG= -g -c

ASFLAG=-g -c

OBJ=start.o main.o

LDFLAGS= -static -L\

#指定浮点库所在的路径

"C:\Program Files\yagarto\lib\gcc\arm-none-eabi\4.6.2" -lgcc

#设置编译模式

%.o:%.S

$(CC) $(ASFLAG) $< -o $@

%.o:%.c

$(CC) $(CFLAG) $< -o $@

all:$(OBJ)

$(LD) -Ttext=0x20000 $^ -o arm.elf $(LDFLAGS)

$(OBJDUMP) -D arm.elf > arm.dis

clean:

$(RM) *.o arm.dis arm.elf

使用硬件浮点实现浮点运算(hard-float)

使用硬件浮点的时候,我们需要给编译器传递一些参数,让编译器编译出硬件浮点单元处理器能识别的指令。

(1)-mfpu=name

参数-mfpu就是用来指定要产生那种硬件浮点运算指令,常用的右vfp和neon等。

浮点协处理器指令:

ARM10 and ARM9: -mfpu=vfp(or vfpv1 or vfpv2) Cortex-A8: -mfpu=neon

(2) -mfloat-abi=value

-mfloat-abi=soft 使用这个参数时,其将调用软浮点库(softfloat lib)来支持对浮点的运算,GCC编译器已经有这个库了,一般在libgcc里面。这时根本不会使用任何浮点指令,而是采用常用的指令来模拟浮点运算。 但使用的ARM芯片不支持硬浮点时,可以考虑使用这个参数。在使用这个参数时,连接时一般会出现下面的提示:

undefined reference to `__aeabi_fdiv'

或者类似的提示,主要因为一般情况下连接器没有去主动寻找软浮点库,这时使用将libgcc库加入即可。

-mfloat-abi=softfp

-mfloat-abi=hard

这两个参数都用来产生硬浮点指令,至于产生哪里类型的硬浮点指令,需要由

-mfpu=xxx参数来指令。这两个参数不同的地方是:

-mfloat-abi=softfp生成的代码采用兼容软浮点调用接口(即使用-mfloat- abi=soft时的调用接口),这样带来的好处是:兼容性和灵活性。库可以采用-mfloat-abi=soft编译,而关键的应用程序可以采用 -mfloat-abi=softfp来编译。特别是在库由第三方发布的情况下。

-mfloat-abi=hard生成的代码采用硬浮点(FPU)调用接口。这样要求所有库和应用程序必须采用这同一个参数来编译,否则连接时会出现接口不兼容错误。

我们对main.c文件使用硬件浮点重新编译:

翻译成的汇编代码如下:

start.s:

.global _start

#define USER_MODE 0x10

_start:

@ 设置为所有模式都可以访问协处理器,cortex-A8手册 3.2.27

mov r0, #0xfffffff

mcr p15, 0, r0, c1, c0, 2

@ 使能NEON and VFP协处理器,NEON and VFP enable bit.

@ 设置fpexc的30位为1去使能NEON and VFP,cortex-A8 手册 13.4.3

ldr r0, =1<<30

fmxr fpexc, r0

@设置CPU为user模式

mov r0,#USER_MODE

msr cpsr_c,r0

@跳到main函数

ldr sp,=0x34000

bl main

stop:

b stop

main.c:

int main()

{

float f1,f2,f3;

f1 = 1.24;

f2 = 1.22;

f3 = f1 + f2;

return 0;

}

Makefile:

CC=arm-none-eabi-gcc

AS=arm-none-eabi-as

LD=arm-none-eabi-ld

OBJDUMP=arm-none-eabi-objdump

RM=rm -rf

CFLAG=-g -c -mfpu=neon -mfloat-abi=softfp

ASFLAG=-g -c -mfpu=neon -mfloat-abi=softfp

OBJ=start.o main.o

#设置编译模式

%.o:%.S

$(CC) $(ASFLAG) $< -o $@

%.o:%.c

$(CC) $(CFLAG) $< -o $@

all:$(OBJ)

$(LD) -Ttext=0x20000 $^ -o arm.elf

$(OBJDUMP) -D arm.elf > arm.dis

clean:

$(RM) *.o arm.dis arm.elf

转自:http://www.eefocus.com/ayayayaya/blog/14-03/302211_6ecdc.html

原文发布于微信公众号 - 程序员互动联盟(coder_online)

原文发表时间:2015-09-11

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏FreeBuf

CVE-2018-8174:从UAF到任意地址读写

2018年5月9日,360发表Blog “Analysis of CVE-2018-8174 VBScript 0day and APT actor relat...

800
来自专栏醒者呆

掌握一门语言Go

摘要:Go语言的优势不必多说,通过本篇文章,让我们花时间来掌握一门外语,Let's Go! 关键字:Go语言,闭包,基本语法,函数与方法,指针,slic...

3449
来自专栏Jack-Cui

第十七天、迷宫游戏

题目 通过让游戏角色自动寻找迷宫出口,走出迷宫,来练习C++面向对象之封装的基础知识。迷宫图如下所示,其中X表示墙。 ? 1、程序分析 走出去的...

2080
来自专栏顶级程序员

全面深入理解Python面向对象编程

面向过程编程最易被初学者接受,其往往用一长段代码来实现指定功能,开发过程中最常见的操作就是粘贴复制,即:将之前实现的代码块复制到现需功能处。

654
来自专栏技术小讲堂

iBatis.Net(6):Data Map(深入)

在上一篇中,我写了几个最最基本的DataMap映射,但是如果仅仅是这些功能的话,那iBatis真就有点愧对它的粉丝啦,我个人的理解,iBatis真的可以让开发者...

2809
来自专栏CDA数据分析师

Python 异常处理完整指南

年前我写了一篇文章 Python classic, static, class and abstract methods,现在似乎到了更新的时候,今天我想来剖析...

20010
来自专栏IT派

全面深入理解Python面向对象编程

面向过程编程最易被初学者接受,其往往用一长段代码来实现指定功能,开发过程中最常见的操作就是粘贴复制,即:将之前实现的代码块复制到现需功能处。

692
来自专栏乐百川的学习频道

设计模式(十九) 备忘录模式

备忘录模式是一种行为型模式,作用是将对象的内部状态保存下来,在必要的时候恢复。备忘录模式可以用于游戏存档恢复、文件的历史记录等场合。 下面是一个简单的代码例子。...

2065
来自专栏Java Web

Java 面试知识点解析(四)——版本特性篇

715
来自专栏一“技”之长

iOS 单例设计模式解读 原

      顾名思义,单例,即是在整个项目中,这个类的对象只能被初始化一次。它的这种特性,可以广泛应用于某些需要全局共享的资源中,比如管理类,引擎类,也可以通过...

672

扫描关注云+社区