【问题标题】:How to switch from hexadecimal to 2^16 system in c++如何在 C++ 中从十六进制切换到 2^16 系统
【发布时间】:2020-01-31 05:27:53
【问题描述】:

我有这样的任务: 用户以十六进制输入数字 N1(str1) 和 N2(str2)。程序必须将数字从十六进制转换为 2^16 系统,并计算 2^16 系统中的数字 N1 和 N2 之和,然后将结果转换为十六进制系统。

我有这样一个想法: 首先从十六进制转换为十进制(我可以这样做)。 然后取每个数模 2 ^ 16 乘以数 N1dec(dec11)(或 N2dec(dec22))的以 2 ^ 16 为底的对数,并将余数写入相应的数组中。这就是我的问题开始的地方。我从十进制到 2^16 系统的转换不起作用。希望你能帮忙。

#include <iostream> 
using namespace std;

int main()
{
//HEX to decimal
const char* const str1 = "101D0";//7A120 = 500000; 101D0 = 66000;   //1F4 = 500=dec1=N1
cout << "Hello!\nFirst number in HEX system is " << str1 << endl;
istringstream is(str1);
int dec1;
is >> hex >> dec1;
if (!is && !is.eof()) throw "dammit!";
cout << "First number in decimal system: " << dec1 << endl;
const char* const str2 = "1567";//5479=dec2=num2
cout << "Second number in HEX system is " << str2 << endl;
istringstream iss(str2);
int dec2;
iss >> hex >> dec2;
if (!iss && !iss.eof()) throw "dammit!";
cout << "Second number in decimal system: " << dec2 << endl;
//

//Decimal to 2^16 system
int dec11 = dec1;//because dec11 will be = 0
int dec22 = dec2;//because dec22 will be = 0

int k = 1 << 16;
cout << "2^16 = " << k << endl;
int intPART1 = log(dec11) / log(k);
cout << "Int part of log2^16 (" << dec11 << ") is " << intPART1 << endl << "So num1 in 2^16 system will look like ";

int *n1 = new int[intPART1 + 1];
for (int i = 0; i <= intPART1; i++)
{
    if (i != 0)
    {
        n1[i] = dec11 % k*(1<<16-1);
        dec11 = dec11 / k;
    }
    else
    {
        n1[i] = dec11 % k;
        dec11 = dec11 / k;
    }
}
for (int i = intPART1; i >= 0; i--)
{
    cout << n1[i] << "   ";
}
cout << endl;
int intPART2 = log(dec22) / log(k);
cout << "Int part of log2^16 (" << dec22 << ") is " << intPART2 << endl << "So num2 in 2^16 system will look like ";

int *n2 = new int[intPART2 + 1];
for (int i = 0; i <= intPART2; i++)
{
    if (i != 0)
    {
        n2[i] = dec22 % k*(1 << 16 - 1);
        dec22 = dec22 / k;
    }
    else
    {
        n2[i] = dec22 % k;
        dec22 = dec22 / k;
    }
}

for (int i = intPART2; i >= 0; i--)
{
    cout << n2[i] << "   ";
}
cout << endl;

【问题讨论】:

  • 这与我的评论无关。 std::stoi 将字符串转换为 int,您可以指定该字符串的基数。
  • 系统的 2^16 你的意思是基数 65536?
  • @Timo 是的,基数65536
  • "base 65536" - 一个数字可以有 65535 个值??你会把 1000000 写成两位数:15 个十进制数字和 16960 个个位数字?
  • 转换应该比您尝试的更直接。每个 base-2^16 数字正好由 4 个 base-16 数字表示。

标签: c++ arrays number-systems


【解决方案1】:

由于这看起来像是一个你想自己解决的学习练习,这里有两个提示。

一个十六进制数字代表四位,因此每个基数为 65,536 的数字由四个十六进制数字组成。因此,您可以读取四位一组的数字,而无需转换为十进制或从十进制转换。您学习解码四个十进制数字的算法同样适用于十六进制,除了乘法将更加高效,因为编译器会将它们优化为左移指令。

您应该使用&lt;stdint.h&gt; 中的uint16_t 类型进行此算术运算,因为它的大小完全正确且无符号。无符号算术溢出被定义为环绕,这是你想要的。有符号溢出是未定义的行为。 (或者 #include &lt;cstdint&gt; 后跟 using std::uint16_t;,如果你愿意的话。)

要在任何基数 b 中添加数字,请将数字的总和以 b 为模。当 b 是 2 的幂时,这会更容易,因为 x86 和许多其他 CPU 都有一个 16 位无符号加法指令,可以在硬件中执行此操作,而在任何没有此功能的机器上,编译器可以将其优化为位掩码&amp; 0xFFFFU。

在这两种情况下,如果需要,您可以使用&lt;&lt; 和&amp; 而不是* 和% 手动写出二进制优化。如果您使用有符号而不是无符号数学,这甚至可能会稍微改进生成的代码。但是,任何现代编译器都足够聪明,可以为您执行这种微优化。最好不要过早优化,编写更易于阅读和理解的代码。

【讨论】:

    【解决方案2】:

    由于十六进制值的基数为 16,假设 16^1 和基数 2^16 可以重新计算为 16^4,我们已经可以看到您的目标基数是源基数的倍数。这使得计算非常简单直接。我们所要做的就是稍微改变一下。

    int hexToInt(char c)
    {
        if (c >= 'a')
            return c - 'a' + 10;
        if (c >= 'A')
            return c - 'A' + 10;
        return c - '0';
    }
    
    // Converts hex to base 2^16. vector[0] holds the MSB.
    std::vector<unsigned short> toBase0x10000(std::string const& hex)
    {
        std::size_t bufSize = hex.size() / 4 + (hex.size() % 4 > 0);
        std::vector<unsigned short> number(bufSize);
    
        int shift = 0;
        int value = 0;
        std::size_t numIndex = number.size();
    
        for (int i = hex.size() - 1; i >= 0; i--)
        {
            value |= hexToInt(hex[i]) << shift;
            shift += 4;
    
            if (shift == 16)
            {            
                number[--numIndex] = static_cast<unsigned short>(value);
                shift = 0;
                value = 0;
            }
        }
    
        if (value != 0)
            number[--numIndex] = static_cast<unsigned short>(value);
    
        return number;
    }
    
    std::string fromBase0x10000(std::vector<unsigned short> const& num)
    {
        std::stringstream ss;
        for (auto&& digit : num)
            ss << std::hex << digit;
        return ss.str();
    }
    

    toBase0x10000 返回一个 std::vector&lt;unsigned short&gt;,因此向量中的每个元素都代表您的 2^16 基数的一位数字(因为 unsigned short 可以保持该值范围)。

    作为一个副作用,此实现支持任何精度数字,因此您不受 int 或 long 等数字类型的值范围的限制。

    Here 是一个完整的例子。

    【讨论】:

    • 为什么要写 std::size_t bufSize = hex.size() / 4 + (hex.size() % 4 > 0);而不是 std::size_t bufSize = hex.size(); ?
    • 它(hex.size ()% 4> 0)是如何工作的?这不是左边与零的比较吗?
    • “a”和“A”有什么区别,为什么我们需要返回c - 'a' + 10?如果我有数字 1F4,为什么 4 - 'A' = -13,而不是 -6,在十六进制系统 'A' 中它是十进制的 '10'。我假设这是由于 ASCII 表造成的,但我不明白是怎么回事。请给我解释一下。
    • @Laura hex.size() / 4 部分是因为向量的类型为 unsigned short,即 16 位。一个十六进制字符 (0-F) 可以完全适合 4 位,因此这两种类型之间的比率为 1/4。然而,1/4 比率也有一个问题,即它并不总是产生一个整数。前任。 “123456789”有 9 个字符。如果我们将它除以 4,我们得到 2.25,整数算术将减少到 2。这就是 + (hex.size() % 4 &gt; 0) 发挥作用的地方。它检查字符串的大小是否可以被 4 整除,如果不是,则将 1 添加到 bufSize(否则表达式为 0)。
    • (hex.size() % 4 &gt; 0) 是一个布尔表达式。在算术中,true 转换为 1,false 转换为 0。
    猜你喜欢
    • 2011-02-19
    • 1970-01-01
    • 2018-11-18
    • 2011-02-04
    • 1970-01-01
    • 2011-06-01
    • 2011-12-09
    • 1970-01-01
    • 2015-04-19
    相关资源
    最近更新 更多