“inti=*(short*)&float”不应该保留符号吗?(C++)

2024-09-28 22:24:12 发布

您现在位置:Python中文网/ 问答频道 /正文

下面的Python3+代码试图编译一个Cpp脚本,并使用它从float转换为int,同时保持内存不变;详情如下:

import sys, os
import numpy as np
import matplotlib.pyplot as plt 

# Build a C++ Script that accepts a str,
# converts it to a float, and prints 
# the result of the operation
def build():
    script = """
#include<iostream>

int main(int argc, char *argv[]){

  float f = std::stof(argv[1]);
  int i = *(short *)&f;


  std::cout << f << " " << i <<std::endl;

  return 0;

}
    """
    with open('script.cpp', 'w') as f:
        f.write(script)

    return 1

# Loads the results from the C++ script
def load_results():
    x,y = [],[]
    with open('results-ctest.txt', 'r') as f:
        result = f.readlines()
    for _ in result:
        local = _.split(' ')
        x.append(float(local[0]))
        y.append(int(local[1][:-2]))

    return x,y

# Plots the results from the C++ script
def show_results(x,y):
    # Define a figure
    f,ax = plt.subplots()

    # Plot results
    ax.scatter(x,y)

    # Format the axis according to the shown figure
    ax.set_xticks(np.linspace(min(x), max(x), 20))
    ax.set_yticks(np.linspace(min(y), max(y), 20))
    plt.show()

if __name__=='__main__':

    # build the C++ script
    build()

    # Compile the C++ script
    # and clean the previous results
    # by removing "results-ctest.txt"
    os.system(f'g++ script.cpp')
    os.system('rm results-ctest.txt')

    # Generate 500 floats between -1.000.000 and 1.000.000
    # and pass them to the C++ script
    numbers=np.linspace(-1e6, 1e6, 500)
    for number in numbers:
        os.system(f'./a.out {number}>> results-ctest.txt')

    # Open the results of the C++ script and 
    # split the input from the output
    x,y = load_results()

    # Produce the figure and open
    # a window for it
    show_results(x,y)

明显的问题是,(输出)整数与(输入)浮点数如下:

output integers vs input floats as computed by the attached python 3+ code

然而,如果“int”和“float”都是根据下图用4个字节实现的,那么输入和输出应该具有相同的符号

float(above) and int(below) 4-byte implementation

总结如下:使用C++创建int,并且它的符号没有按照第一个图所示保存。

  float f = std::stof(argv[1]);
  int i = *(short *)&f;

多谢各位


编辑: 底线是有一个打字错误。 我编辑问题是为了显示“正确”的情节

如评论中所述,问题在于以下几行:

int i = *(short *)&f;

应该是:

int i = *(int *)&f;

从而得出以下图表: Results after fixing the typo


Tags: andtheimporttxtosasnpscript
1条回答
网友
1楼 · 发布于 2024-09-28 22:24:12

代码的第一个问题是,将一种类型的数据作为另一种不相关的类型读取(没有某些属性,如公共前缀),或者使用一些类型(如std::bytechar),这是一种未定义的行为

std::bit_cast是一种正确执行的方法

第二个问题是,精确位的含义会因计算机的端度和使用的浮点标准等因素而有所不同。现在这些都是相对标准的,但还不完全

第三个问题是,short、int和float的大小是特定于平台和编译器的。您可以使用固定大小的整数类型,如std::int32_t,您应该使用它而不是intshort。通常short是16位int是32位,但这远不是通用的float32位确实很常见

因此:

std::int32_t i = std::bit_cast<std::int32_t>(f);

std::cout << f << " " << i <<std::endl;

至少可以解决大部分疯狂的问题

我不知道从浮点转换为整数时,endianness转换会有什么问题。我想说的是:

std::uint32_t ui = std::bit_cast<std::uint32_t>(f);
std::cout << f << " 0b";
for (int i = 0; i < 32; ++i)
  std::cout << (ui&(1<<i));

std::int32_t i = std::bit_cast<std::int32_t>(f);
std::cout << " " << i <<std::endl;

也可以根据体系结构的端性来转储f的位。然后取一个浮点值,它的位表示形式是已知的(并且不是所有的0),看看这会产生什么

相关问题 更多 >