理解负数并进行转换

Understanding negative numbers and converting them

本文关键字:转换      更新时间:2023-10-16

这似乎是一个相当大的主题。例如,如果您尝试将-ve float强制转换(转换)为+ve unsigned int,则不会工作。所以我现在正在阅读关于2的补码,提升和位模式,以及如何转换/处理-ve到+ve的浮点数/整数。例如,在VS 2010的示例中,x保持为-1。

float x = -1;
(unsigned int)y = (unsigned int)x;
printf("y:%u", y);

那么负整数在内存中是如何以位模式存储的,c++中有哪些选项可以转换它们,可以通过位移位来实现吗,最好的方法是什么

那么负整数在内存中是如何以位模式存储的呢

为了更好地理解负整数值的表示,使用下面的代码来操作它:

#include <iostream>
#include <bitset>
#include <cstdint>
void printBitWise(std::ostream& os, uint8_t* data, size_t size) {
    for(size_t i = 0; i < size; ++i) {
        for(uint8_t j = 0; j < 8; ++j) {
            if((data[i] >> j) & 1) {
                os << '1';
            }
            else {
                os << '0';
            }
        }
    }
}
int main() {
    int x = -1;
    std::bitset<sizeof(int) * 8> bitwise1(x);   
    std::cout << bitwise1.to_string() << std::endl;
    int y = -2;
    std::bitset<sizeof(int) * 8> bitwise2(y);
    std::cout << bitwise2.to_string() << std::endl;
    float a = -1;
    printBitWise(std::cout,reinterpret_cast<uint8_t*>(&a),sizeof(float));
    std::cout << std::endl;
    double b = -1;
    printBitWise(std::cout,reinterpret_cast<uint8_t*>(&b),sizeof(double));
    std::cout << std::endl;
    float c = -2;
    printBitWise(std::cout,reinterpret_cast<uint8_t*>(&c),sizeof(float));
    std::cout << std::endl;
    double d = -2;
    printBitWise(std::cout,reinterpret_cast<uint8_t*>(&d),sizeof(double));
    std::cout << std::endl;
    return 0;
}
输出:

11111111111111111111111111111111
11111111111111111111111111111110
00000000000000000000000111111101
0000000000000000000000000000000000000000000000000000111111111101
00000000000000000000000000000011
0000000000000000000000000000000000000000000000000000000000000011

floatdouble值的位格式是另一回事。它是用IEEE浮点格式描述的,并且可能是特定于特定行为的编译器实现(例如'舍入规则''操作')。

在程序中,变量x是float类型。机器需要把它转换成整型。对于intel处理器,指令是"cvttss2si"。请查看http://en.wikipedia.org/wiki/Single-precision_floating-point_format查看float在二进制格式中是如何表示的。

对于你给出的代码片段,我用g++和VS 2013进行了测试。两者都按预期工作并打印"y:-1"。

#include <cstdio>
int main()   
{
    float x = -1;
    unsigned int y;
    y = (unsigned int)x;
    printf("y:%d", y);
    return 0;
}

然而,在这个程序中,编译器为我们完成了浮点型到整型的转换。

movl    $-1, %eax
movl    %eax, -12(%rbp)
movl    -12(%rbp), %esi
movb    $0, %al
callq   _printf

下面的示例程序可以揭示机器如何进行浮点数到整数的转换:

#include <cstdio>
int main()
{
    float x ;
    scanf("%f", &x);
    unsigned int y;
    y = (unsigned int)x;
    printf("y:%d", y);
    return 0;
}

下面是cvttss2si完成浮点数到整数转换工作的程序集(http://www.jaist.ac.jp/iscenter-new/mpc/altix/altixdata/opt/intel/vtune/doc/users_guide/mergedProjects/analyzer_ec/mergedProjects/reference_olh/mergedProjects/instructions/instruct32_hh/vc68.htm)。

cvttss2si   -8(%rbp), %rsi
movl    %esi, %ecx
movl    %ecx, -12(%rbp)
movl    -12(%rbp), %esi
movq    -24(%rbp), %rdi         ## 8-byte Reload
movl    %eax, -28(%rbp)         ## 4-byte Spill
movb    $0, %al
callq   _printf

在许多平台上,数字的符号由保留位表示。

对于双补位整数,最高有效位(MSB)表示符号,设置时为负值,清除时为正值。但是,设置位可能不能正确地将值从正转换为负。

在许多浮点格式中,都保留了一个位来表示数字的符号。您必须研究各种浮点标准格式,特别是您的平台和编译器使用的格式。

从负数到正数的最佳和最便携的方法是使用abs族函数。记住,这是有符号数据类型。

要从正数转换为负数,请乘以-1或-1.0。

unsigned类型没有定义负数。