GVKun编程网logo

c – 将int32重新解释为float(c语言把int改成float)

19

最近很多小伙伴都在问c–将int32重新解释为float和c语言把int改成float这两个问题,那么本篇文章就来给大家详细解答一下,同时本文还将给你拓展.net–为什么将Int32转换为Float6

最近很多小伙伴都在问c – 将int32重新解释为floatc语言把int改成float这两个问题,那么本篇文章就来给大家详细解答一下,同时本文还将给你拓展.net – 为什么将Int32转换为Float64会导致数据发生变化?、Angular 8.3.2:将ArrayBuffer转换为Float32Array、assembly – 使用Bitwise将Int转换为Float/Float到Int、assembly – 将uint32的向量转换为float向量的最有效方法?等相关知识,下面开始了哦!

本文目录一览:

c – 将int32重新解释为float(c语言把int改成float)

c – 将int32重新解释为float(c语言把int改成float)

我需要保存一个浮点值,它是一个整数值的复制内存.
在reinterpretedFloat函数中,我创建了一个样本整数并将内存复制到float变量.
当memcpy-ed float返回时,值就会发生变化.

这是示例代码.

#include <stdio.h>
#include <stdint.h>

void printHex(const unsigned char* buff,int count)
{
    printf("0X");
    for (int i = 0; i < count; ++i)
    {
        printf("\t%X",buff[i]);
    }
    printf("\n");
}

float reinterpretedFloat()
{
    int32_t value = 0x7F845E58;
    float tmp;
    memcpy(&tmp,&value,sizeof(float));
    printHex(reinterpret_cast<const unsigned char*>(&tmp),4); //memcpy
    return tmp;
}

int main()
{
    float newFloat = reinterpretedFloat();
    printHex(reinterpret_cast<const unsigned char*>(&newFloat),4); //returned value

    return 0;
}

结果就是这样.

0X      58      5E      84      7F(memcpy)
0X      58      5E      C4      7F(returned value)

我的预期是0X 58 5E 84 7F ……

任何机构都可以解释为什么会这样?
在x64配置中,这不会发生.

解决方法

0x7f845e58是 signaling NaN.它被归一化为0x7fc45e58,这是一个具有相同有效载荷的安静NaN.

x86-64和32位x86结果之间的区别是因为在前一种模式下,要从reinterpretedFloat()函数返回浮点值,来自SSE ISA扩展的MOVSS指令将值加载到xmm0寄存器中而不进行任何转换,而在后者使用FLD dword […],它将32位浮点数转换为x87内部80位长双精度格式,将信号状态归一化为quiet *.

机制上的差异是由于x86-64体系结构保证支持SSE,因此ABI使用它,而i386 ABI不需要它,因为并非所有x86 cpu都支持它.

*从技术上讲,转换会导致无效操作异常,但由于它被屏蔽(默认情况下),因此您可以获得从NaN中删除信令状态的规范化结果

.net – 为什么将Int32转换为Float64会导致数据发生变化?

.net – 为什么将Int32转换为Float64会导致数据发生变化?

我正在教自己CIL并且到目前为止一直做得很好(昨天真的开始)但我遇到了一个我无法弄清楚的问题.我正在提示用户输入一个int(int32),然后将其存储并转换为浮点并显示它.然而,无论我输入什么都是不同的浮动.这是我的代码:

.assembly variables {}
.method public static void main() cil managed
{
    .entrypoint
    .maxstack 8
    .locals init (float64)

    ldstr "Enter a digit: "
    call void [mscorlib]System.Console::WriteLine(string)
    call int32 [mscorlib]System.Console::Read()
    conv.r8
    stloc.0
    ldstr "as a float: "
    call void [mscorlib]System.Console::WriteLine(string)
    ldloc.0
    dup
    call void [mscorlib]System.Console::Write(float64)
    stloc.0
    ldstr "Stored in location 0"
    call void [mscorlib]System.Console::WriteLine(string)
    ldloc.0
    conv.i4
    call void [mscorlib]System.Console::WriteLine(int32)
    call int32 [mscorlib]System.Console::Read() // to pause before closing window
    pop
    ret
}

我只是在和CIL搞砸,但我觉得为了清晰起见,我会抛弃我的整个例子.它编译得很好但是当我输入5时它返回53作为浮点数和转换后的int32.

有人可以说明我做错了什么!

编辑:感谢Marc Gravell,我能够弄明白.对于那些感兴趣的人,这里是正确的代码:

.assembly variables {}
.method public static void main() cil managed
{
    .entrypoint
    .maxstack 8
    .locals init (float64)

    ldstr "Enter a digit: "
    call void [mscorlib]System.Console::WriteLine(string)
    call string [mscorlib]System.Console::ReadLine()
    call int32 [mscorlib]system.int32::Parse(string)
    conv.r8
    stloc.0
    ldstr "as a float: "
    call void [mscorlib]System.Console::WriteLine(string)
    ldloc.0
    dup
    call void [mscorlib]System.Console::Write(float64)
    stloc.0
    ldstr "Stored in location 0"
    call void [mscorlib]System.Console::WriteLine(string)
    ldloc.0
    conv.i4
    call void [mscorlib]System.Console::WriteLine(int32)
    call int32 [mscorlib]System.Console::Read() // to pause before closing window
    pop
    ret
}

解决方法

Console.Read返回Unicode代码点,或者为EOF返回-1. 53是字符(非整数)’5’的代码点.

您也许可以使用Console.ReadLine和int.Parse.

Angular 8.3.2:将ArrayBuffer转换为Float32Array

Angular 8.3.2:将ArrayBuffer转换为Float32Array

以下代码有效:

this.wsSubscription = this.webSocket.createObservableSocket ("ws://localhost:8080")
  .subscribe (
    data => 
    {
         var bufferPromise = data.arrayBuffer();
         data.arrayBuffer().then (buffer =>{
         var arr32 = new Float32Array (buffer);
    }

assembly – 使用Bitwise将Int转换为Float/Float到Int

assembly – 使用Bitwise将Int转换为Float/Float到Int

我想知道你是否可以帮助解释将整数转换为float或float转换为整数的过程.对于我的课程,我们只使用按位运算符来完成此操作,但我认为从类型到类型的强制理解将在这个阶段帮助我更多.

根据我目前所知,对于int to float,你必须将整数转换为二进制,通过查找有效数,指数和分数来规范化整数的值,然后从那里输出float中的值?

至于float到int,你必须将值分成有效数,指数和分数,然后反转上面的指令得到一个int值?

我试着按照这个问题的说明:Casting float to int (bitwise) in C

但我真的无法理解它.

另外,有人可以解释为什么在将int转换为float时大于23位的值需要舍入?

提前致谢

解决方法

首先,你应该考虑阅读一篇论文,如果你想更好地理解浮点弱点:“每个计算机科学家应该知道浮点运算,” http://www.validlab.com/goldberg/paper.pdf

现在来一些肉.

下面的代码是简单的,并且试图从0的范围内的unsigned int产生IEEE-754单精度浮点数.价值< 224.这是您最有可能在现代硬件上遇到的格式,它是您在原始问题中引用的格式. IEEE-754单精度浮点数分为三个字段:单符号位,8位指数和23位有效数(有时称为尾数). IEEE-754使用隐藏的1有效数,意味着有效数实际上是24位.这些位从左到右打包,符号位在第31位,指数在第30位…… 23位,有效位在位22 .. 0中.来自维基百科的下图说明: 指数的偏差为127,这意味着与浮点数关联的实际指数比指数字段中存储的值小127.因此,指数0将被编码为127. (注意:完整的维基百科文章可能对您有意思.参考:http://en.wikipedia.org/wiki/Single_precision_floating-point_format)

因此,IEEE-754号码0x40000000解释如下:

>位31 = 0:正值
>位30 .. 23 = 0x80:指数= 128 – 127 = 1(又称21)
>位22 .. 0均为0:有效值= 1.00000000_00000000_0000000. (注意我恢复了隐藏的1).

所以值是1.0 x 21 = 2.0.

要在上面给出的有限范围内转换unsigned int,然后转换为IEEE-754格式的东西,您可以使用类似下面的函数.它采取以下步骤:

>将整数的前导1与浮点表示中隐藏1的位置对齐.
>在对齐整数时,记录所做的轮班总数.
>掩盖隐藏的1.
>使用所做的班次数,计算指数并将其附加到数字上.
>使用reinterpret_cast,将生成的位模式转换为浮点数.这部分是一个丑陋的黑客,因为它使用类型惩罚指针.你也可以通过滥用工会来做到这一点.某些平台提供内在操作(例如_itof)以使这种重新解释不那么难看.

有更快的方法可以做到这一点;如果不是超级有效的话,这个是教学上有用的:

float uint_to_float(unsigned int significand)
{
    // Only support 0 < significand < 1 << 24.
    if (significand == 0 || significand >= 1 << 24)
        return -1.0;  // or abort(); or whatever you'd like here.

    int shifts = 0;

    //  Align the leading 1 of the significand to the hidden-1 
    //  position.  Count the number of shifts required.
    while ((significand & (1 << 23)) == 0)
    {
        significand <<= 1;
        shifts++;
    }

    //  The number 1.0 has an exponent of 0,and would need to be
    //  shifted left 23 times.  The number 2.0,however,has an
    //  exponent of 1 and needs to be shifted left only 22 times.
    //  Therefore,the exponent should be (23 - shifts).  IEEE-754
    //  format requires a bias of 127,though,so the exponent field
    //  is given by the following expression:
    unsigned int exponent = 127 + 23 - shifts;

    //  Now merge significand and exponent.  Be sure to strip away
    //  the hidden 1 in the significand.
    unsigned int merged = (exponent << 23) | (significand & 0x7FFFFF);


    //  Reinterpret as a float and return.  This is an evil hack.
    return *reinterpret_cast< float* >( &merged );
}

您可以使用检测数字中前导1的函数来提高此过程的效率. (这些有时会出现像clz这样的名称,用于“计数前导零”,或者用于“标准化”的标准.)

您还可以通过记录符号,取整数的绝对值,执行上述步骤,然后将符号放入数字的第31位,将其扩展为有符号数.

对于整数> = 224,整个整数不适合32位浮点格式的有效数字段.这就是你需要“舍入”的原因:你失去了LSB以使价值合适.因此,多个整数将最终映射到相同的浮点模式.确切的映射取决于舍入模式(向-Inf舍入,向Inf舍入,向零舍入,向最近偶数舍入).但事实是你不能将24位推到少于24位而没有一些损失.

您可以根据上面的代码看到这一点.它通过将前导1对齐到隐藏的1位置来工作.如果值>> 224,则代码​​需要向右移动而不是向左移动,这必然会使LSB移位.舍入模式只是告诉您如何处理移位的位.

assembly – 将uint32的向量转换为float向量的最有效方法?

assembly – 将uint32的向量转换为float向量的最有效方法?

x86没有从无符号int32转换为浮点的SSE指令.实现这一目标的最有效指令序列是什么?

编辑:
为了澄清,我想做以下标量操作的向量序列:

unsigned int x = ...
float res = (float)x;

EDIT2:这是一个用于进行标量转换的简单算法.

unsigned int x = ...
float bias = 0.f;
if (x > 0x7fffffff) {
    bias = (float)0x80000000;
    x -= 0x80000000;
}
res = signed_convert(x) + bias;

解决方法

您的天真标量算法无法提供正确的舍入转换 – 它会在某些输入上遭受双舍入.举个例子:如果x是0x88000081,那么转换为float的正确舍入结果是2281701632.0f,但是你的标量算法将返回2281701376.0f.

在我的头顶,你可以做如下正确的转换(正如我所说,这是我的头顶,所以它可能在某处保存指令):

movdqa   xmm1,xmm0    // make a copy of x
psrld    xmm0,16      // high 16 bits of x
pand     xmm1,[mask]   // low 16 bits of x
orps     xmm0,[onep39] // float(2^39 + high 16 bits of x)
cvtdq2ps xmm1,xmm1     // float(low 16 bits of x)
subps    xmm0,[onep39] // float(high 16 bits of x)
addps    xmm0,xmm1    // float(x)

常量具有以下值:

mask:   0000ffff 0000ffff 0000ffff 0000ffff
onep39: 53000000 53000000 53000000 53000000

这样做是将每个通道的高半部分和低半部分分别转换为浮点数,然后将这些转换后的值相加.因为每一半只有16位宽,所以转换为float不会产生任何舍入.仅在添加两半时才进行舍入;因为加法是一个正确舍入的操作,所以整个转换都是正确舍入的.

相比之下,你的天真实现首先将低31位转换为浮点数,这会导致舍入,然后有条件地将2 ^ 31加到该结果,这可能会导致第二次舍入.每当你在转换中有两个单独的舍入点时,除非你非常小心它们是如何发生的,否则你不应该期望结果被正确舍入.

关于c – 将int32重新解释为floatc语言把int改成float的介绍现已完结,谢谢您的耐心阅读,如果想了解更多关于.net – 为什么将Int32转换为Float64会导致数据发生变化?、Angular 8.3.2:将ArrayBuffer转换为Float32Array、assembly – 使用Bitwise将Int转换为Float/Float到Int、assembly – 将uint32的向量转换为float向量的最有效方法?的相关知识,请在本站寻找。

本文标签:

上一篇CentOS6.4下安装qt4.8.5(centos6.5如何安装)

下一篇运送libstdc .so.6与应用程序(运送系统)