c:更改变量类型而不进行强制转换

时间:2015-06-03 14:05:02

标签: c types casting

我正在将uint32_t更改为float而不更改实际位。

只是为了确定:我不想施放它。所以float f = (float) i与我不想做的完全相反,因为它会改变位。

我将使用它将我的(伪)随机数转换为浮点数而不进行不必要的数学运算。

我目前正在做的事情以及已经在做的是:

float random_float( uint64_t seed ) {

    // Generate random and change bit format to ieee
    uint32_t asInt = (random_int( seed ) & 0x7FFFFF) | (0x7E000000>>1);

    // Make it a float
    return *(float*)(void*)&asInt; // <-- pretty ugly and nees a variable
}                                                                      

问题:现在我想摆脱asInt变量,我想知道是否有更好/不那么丑陋的方式然后获取地址这个变量,将它转换两次并再次取消引用它?

3 个答案:

答案 0 :(得分:6)

你可以尝试联合 - 只要你确保类型的内存大小相同:

union convertor {
    int asInt;
    float asFloat;
};

然后你可以将你的int分配给asFloat(或者如果你愿意,可以将其他方式分配)。当我需要一方面进行按位操作并且另一方面仍然在数字上获得uint32_t表示时,我会使用它很多

[编辑]
像许多评论员正确陈述的那样,你必须考虑像NAN,+ INF,-INF,+ 0,-0这样的整数无法呈现的值。

答案 1 :(得分:1)

因此,您似乎希望根据代码生成介于0.5和1.0之间的浮点数。

假设您的微控制器具有支持浮点的标准C库,您可以在不涉及任何浮点运算的情况下执行所有标准兼容,您只需要ldexp函数本身不会实际上做任何浮点数学。

这看起来像这样:

return ldexpf((1 << 23) + random_thing_smaller_than_23_bits(), -24);

这里的诀窍是我们碰巧知道IEEE754 binary32浮点数在2 ^ 23和2 ^ 24之间具有整数精度(我可以在这里逐个检查,请仔细检查,我翻译)这是我在双打上做过的一些工作。因此编译器应该知道如何将该数字转换为浮点数。然后ldexp只需更改指数中的位,即可将该数字乘以2 ^ -24。没有实际的浮点运算,也没有未定义的行为,代码完全可移植到任何带有IEEE754数字的标准C实现。仔细检查生成的代码,但是一个好的编译器和c库不应该在这里使用任何浮点指令。

如果您想查看一些实验,我已经完成了生成随机浮点数you can peek at this github repo。这完全是关于双打的,但应该可以简单地翻译成浮点数。

答案 2 :(得分:0)

将int的二进制表示重新解释为float会导致重大问题:

  • 浮点数的二进制表示中有很多未定义的代码。
  • 其他代码代表特殊条件,如NAN,+ INF,-INF,+ 0,-0(sic!)等。

此外,如果这是一个随机值,即使捕获所有非值表示,也会产生非常糟糕的随机分布。

如果您正在使用没有FPU的MCU,那么最好考虑避免浮动。替代方案可能是分数或缩放整数。有许多算法实现使用float,但可以很容易地转换为具有可接受的精度损失的固定点类型(甚至根本没有)。有些甚至可能比float更精确(注意单个精度浮点只有23位尾数,int32有31位(+ 1个符号),对于小数或固定的缩放int也是如此。

请注意,C11为_Frac添加了(可选)支持。你可能想研究一下。

修改

根据您的评论,您似乎将int转换为0范围内的浮点数。&lt; 1。为此,您可以使用uint32_t(例如原始值)上的位操作来组合浮点数。您只需要遵循IEEE格式(假设您的工具链符合C标准!请参阅wikipedia

结果(仍然是uint32_t)然后可以由其他人已经描述的联合或指针重新解释。将其打包在依赖于系统的,评论良好的库中并深入挖掘。不要忘记检查endianess和alignment(对于float和uint32_t可能都是相同的,但对于bit-ops很重要)。