如何在 C++ 中从十六进制切换到 2^16 系统
How to switch from hexadecimal to 2^16 system in c++
我有这样的任务:
用户以十六进制输入数字 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;
由于十六进制值以 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
returns a std::vector<unsigned short>
因此向量中的每个元素代表您的基数 2^16 数字的一位(因为 unsigned short
可以保持该值范围).
作为副作用,此实现支持任何精度数字,因此您不受 int
或 long
.
等数字类型的值范围限制
Here 是一个完整的例子。
由于这看起来像是您想要自己解决的学习练习,这里有两个提示。
一个十六进制数字代表四位,因此每个 base-65,536 数字由四个十六进制数字组成。因此,您可以读取四位一组的数字,而无需转换为十进制或从十进制转换为十进制。您学习解码四位十进制数字的相同算法也适用于十六进制,除了乘法会更有效,因为编译器会将它们优化为左移指令。
对于此算法,您应该使用 <stdint.h>
中的 uint16_t
类型,因为它的大小恰到好处且无符号。无符号算术溢出被定义为环绕,这就是你想要的。有符号溢出是未定义的行为。 (或者 #include <cstdint>
后跟 using std::uint16_t;
,如果你愿意的话。)
要在任何基数 b 中添加数字,请对数字之和取模 b。当 b 是 2 的幂时,这会更容易,因为 x86 和许多其他 CPU 有一个 16 位无符号加法指令,可以在硬件和任何不这样做的机器上执行此操作't,编译器可以将其优化为位掩码 & 0xFFFFU
.
在这两种情况下,如果需要,您可以使用 <<
和 &
而不是 *
和 %
手动写出二进制优化。如果您使用有符号而不是无符号数学,这甚至可能会稍微改进生成的代码。然而,任何现代编译器都足够智能,可以为您执行这种微优化。您最好不要过早优化,编写更易于阅读和理解的代码。
我有这样的任务: 用户以十六进制输入数字 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;
由于十六进制值以 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
returns a std::vector<unsigned short>
因此向量中的每个元素代表您的基数 2^16 数字的一位(因为 unsigned short
可以保持该值范围).
作为副作用,此实现支持任何精度数字,因此您不受 int
或 long
.
Here 是一个完整的例子。
由于这看起来像是您想要自己解决的学习练习,这里有两个提示。
一个十六进制数字代表四位,因此每个 base-65,536 数字由四个十六进制数字组成。因此,您可以读取四位一组的数字,而无需转换为十进制或从十进制转换为十进制。您学习解码四位十进制数字的相同算法也适用于十六进制,除了乘法会更有效,因为编译器会将它们优化为左移指令。
对于此算法,您应该使用 <stdint.h>
中的 uint16_t
类型,因为它的大小恰到好处且无符号。无符号算术溢出被定义为环绕,这就是你想要的。有符号溢出是未定义的行为。 (或者 #include <cstdint>
后跟 using std::uint16_t;
,如果你愿意的话。)
要在任何基数 b 中添加数字,请对数字之和取模 b。当 b 是 2 的幂时,这会更容易,因为 x86 和许多其他 CPU 有一个 16 位无符号加法指令,可以在硬件和任何不这样做的机器上执行此操作't,编译器可以将其优化为位掩码 & 0xFFFFU
.
在这两种情况下,如果需要,您可以使用 <<
和 &
而不是 *
和 %
手动写出二进制优化。如果您使用有符号而不是无符号数学,这甚至可能会稍微改进生成的代码。然而,任何现代编译器都足够智能,可以为您执行这种微优化。您最好不要过早优化,编写更易于阅读和理解的代码。