在 C++ 中没有外部库的情况下将 128 位从字符数组转换为十进制
converting 128 bits from a character array to decimal without external libraries in C++
我必须将大小为 16(每个字符 1 个字节)的字符数组的 128 位转换为十进制和十六进制,而不使用任何其他库。将其转换为十六进制很容易,因为每次处理四位,并且在生成后立即为每四位打印结果。
但是说到小数。不可能以正常的数学方式转换它,其中每个位乘以 2 的幂从左开始的位索引。
所以我想通过逐位打印来像处理十六进制那样转换它。但问题是,在十进制中,这是不可能的,因为最大数字是 9,它需要 4 位来表示,而 4 位可以表示最多 15 的十进制数。我尝试制作一些机制来携带额外的部分,但不能想办法做到这一点。我认为,这也行不通。我已经漫无目的地尝试了三天,因为我不知道该做什么。甚至无法在互联网上找到任何有用的解决方案。
所以,我想要一些方法来完成这项工作。
这是我的完整代码:
#include <iostream>
#include <cstring>
#include <cmath>
using namespace std;
const int strng = 128;
const int byts = 16;
class BariBitKari {
char bits_ar[byts];
public:
BariBitKari(char inp[strng]) {
set_bits_ar(inp);
}
void set_bits_ar(char in_ar[strng]) {
char b_ar[byts];
cout << "Binary 1: ";
for (int i=0, j=0; i<byts; i++) {
for (int k=7; k>=0; k--) {
if (in_ar[j] == '1') {
cout << '1';
b_ar[i] |= 1UL << k;
}
else if (in_ar[j] == '0') {
cout << '0';
b_ar[i] &= ~(1UL << k);
}
j++;
}
}
cout << endl;
strcpy(bits_ar, b_ar);
}
char * get_bits_ar() {
return bits_ar;
}
// Functions
void print_deci() {
char b_ar[byts];
strcpy(b_ar, get_bits_ar());
int sum = 0;
int carry = 0;
cout << "Decimal : ";
for (int i=byts-1; i >= 0; i--){
for (int j=4; j>=0; j-=4) {
char y = (b_ar[i] << j) >> 4;
// sum = 0;
for (int k=0; k <= 3; k++) {
if ((y >> k) & 1) {
sum += pow(2, k);
}
}
// sum += carry;
// if (sum > 9) {
// carry = 1;
// sum -= 10;
// }
// else {
// carry = 0;
// }
// cout << sum;
}
}
cout << endl;
}
void print_hexa() {
char b_ar[byts];
strcpy(b_ar, get_bits_ar());
char hexed;
int sum;
cout << "Hexadecimal : 0x";
for (int i=0; i < byts; i++){
for (int j=0; j<=4; j+=4) {
char y = (b_ar[i] << j) >> 4;
sum = 0;
for (int k=3; k >= 0; k--) {
if ((y >> k) & 1) {
sum += pow(2, k);
}
}
if (sum > 9) {
hexed = sum + 55;
}
else {
hexed = sum + 48;
}
cout << hexed;
}
}
cout << endl;
}
};
int main() {
char ar[strng];
for (int i=0; i<strng; i++) {
if ((i+1) % 8 == 0) {
ar[i] = '0';
}
else {
ar[i] = '1';
}
}
BariBitKari arr(ar);
arr.print_hexa();
arr.print_deci();
return 0;
}
要将 128 位数字转换为“十进制”字符串,我将假设大十进制值只需要包含在一个字符串中,并且我们只是在“正数”中" space。在不使用适当的大数库的情况下,我将演示一种将任何字节数组转换为十进制字符串的方法。这不是最有效的方法,因为它会不断地解析、复制和扫描数字字符串。
我们将利用以下事实:
0x87654321 == 2,271,560,481
可以转换为以 8 位块移位的一系列字节。加回这些移位的块会得到原始值
0x87 << 24 == 0x87000000 == 2,264,924,160
0x65 << 16 == 0x00650000 == 6,619,136
0x43 << 8 == 0x00004300 == 17,152
0x21 << 0 == 0x00000021 == 33
Sum == 0x87654321 == 2,271,560,481
所以我们将 128 位数字转换为字符串的策略是:
将原始的 16 字节数组转换为 16 个字符串 - 每个字符串代表数组每个字节的十进制等效值
根据数组中原始字节的索引,将每个字符串“左移”适当的位数。利用左移相当于乘以2的事实
将所有这些移位的字符串加在一起
因此,为了实现这一点,我们引入了一个函数,可以将两个字符串(仅由数字组成)“相加”:
// s1 and s2 are string consisting of digits chars only ('0'..'9')
// This function will compute the "sum" for s1 and s2 as a string
string SumStringValues(const string& s1, const string& s2)
{
string result;
string str1=s1, str2=s2;
// make str2 the bigger string
if (str1.size() > str2.size())
{
swap(str1, str2);
}
// pad zeros onto the the front of str1 so it's the same size as str2
while (str1.size() < str2.size())
{
str1 = string("0") + str1;
}
// now do the addition operation as loop on these strings
size_t len = str1.size();
bool carry = false;
while (len)
{
len--;
int d1 = str1[len] - '0';
int d2 = str2[len] - '0';
int sum = d1 + d2 + (carry ? 1 : 0);
carry = (sum > 9);
if (carry)
{
sum -= 10;
}
result.push_back('0' + sum);
}
if (carry)
{
result.push_back('1');
}
std::reverse(result.begin(), result.end());
return result;
}
接下来,我们需要一个函数来对十进制字符串进行“左移”:
// s is a string of digits only (interpreted as decimal number)
// This function will "shift left" the string by N bits
// Basically "multiplying by 2" N times
string ShiftLeftString(const string& s, size_t N)
{
string result = s;
while (N > 0)
{
result = SumStringValues(result, result); // multiply by 2
N--;
}
return result;
}
然后把字节数组转成十进制字符串放在一起:
string MakeStringFromByteArray(unsigned char* data, size_t len)
{
string result = "0";
for (size_t i = 0; i < len; i++)
{
auto tmp = to_string((unsigned int)data[i]); // byte to decimal string
tmp = ShiftLeftString(tmp, (len - i - 1) * 8); // shift left
result = SumStringValues(result, tmp); // sum
}
return result;
}
现在让我们在上面使用的原始 32 位值上进行测试:
int main()
{
// 0x87654321
unsigned char data[4] = { 0x87,0x65,0x43,0x21 };
cout << MakeStringFromByteArray(data, 4) << endl;
return 0;
}
生成的程序将打印出来:2271560481
- 同上。
现在让我们在 16 字节的值上尝试一下:
int main()
{
// 0x87654321aabbccddeeff432124681111
unsigned char data[16] = { 0x87,0x65,0x43,0x21,0xaa,0xbb,0xcc,0xdd,0xee,0xff,0x43,0x21,0x24,0x68,0x11,0x11 };
std::cout << MakeStringFromByteArray(data, sizeof(data)) << endl;
return 0;
}
以上打印:179971563002487956319748178665913454865
我们将使用 python 来仔细检查我们的结果:
Python 3.8.3 (tags/v3.8.3:6f8c832, May 13 2020, 22:37:02) [MSC v.1924 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> int("0x87654321aabbccddeeff432124681111", 16)
179971563002487956319748178665913454865
>>>
我觉得不错。
我最初有一个实现可以在 32 位块而不是 8 位块中进行分块和求和。但是,涉及到小端与大端字节顺序问题。我将把潜在的优化作为改天的练习。
我必须将大小为 16(每个字符 1 个字节)的字符数组的 128 位转换为十进制和十六进制,而不使用任何其他库。将其转换为十六进制很容易,因为每次处理四位,并且在生成后立即为每四位打印结果。
但是说到小数。不可能以正常的数学方式转换它,其中每个位乘以 2 的幂从左开始的位索引。
所以我想通过逐位打印来像处理十六进制那样转换它。但问题是,在十进制中,这是不可能的,因为最大数字是 9,它需要 4 位来表示,而 4 位可以表示最多 15 的十进制数。我尝试制作一些机制来携带额外的部分,但不能想办法做到这一点。我认为,这也行不通。我已经漫无目的地尝试了三天,因为我不知道该做什么。甚至无法在互联网上找到任何有用的解决方案。
所以,我想要一些方法来完成这项工作。
这是我的完整代码:
#include <iostream>
#include <cstring>
#include <cmath>
using namespace std;
const int strng = 128;
const int byts = 16;
class BariBitKari {
char bits_ar[byts];
public:
BariBitKari(char inp[strng]) {
set_bits_ar(inp);
}
void set_bits_ar(char in_ar[strng]) {
char b_ar[byts];
cout << "Binary 1: ";
for (int i=0, j=0; i<byts; i++) {
for (int k=7; k>=0; k--) {
if (in_ar[j] == '1') {
cout << '1';
b_ar[i] |= 1UL << k;
}
else if (in_ar[j] == '0') {
cout << '0';
b_ar[i] &= ~(1UL << k);
}
j++;
}
}
cout << endl;
strcpy(bits_ar, b_ar);
}
char * get_bits_ar() {
return bits_ar;
}
// Functions
void print_deci() {
char b_ar[byts];
strcpy(b_ar, get_bits_ar());
int sum = 0;
int carry = 0;
cout << "Decimal : ";
for (int i=byts-1; i >= 0; i--){
for (int j=4; j>=0; j-=4) {
char y = (b_ar[i] << j) >> 4;
// sum = 0;
for (int k=0; k <= 3; k++) {
if ((y >> k) & 1) {
sum += pow(2, k);
}
}
// sum += carry;
// if (sum > 9) {
// carry = 1;
// sum -= 10;
// }
// else {
// carry = 0;
// }
// cout << sum;
}
}
cout << endl;
}
void print_hexa() {
char b_ar[byts];
strcpy(b_ar, get_bits_ar());
char hexed;
int sum;
cout << "Hexadecimal : 0x";
for (int i=0; i < byts; i++){
for (int j=0; j<=4; j+=4) {
char y = (b_ar[i] << j) >> 4;
sum = 0;
for (int k=3; k >= 0; k--) {
if ((y >> k) & 1) {
sum += pow(2, k);
}
}
if (sum > 9) {
hexed = sum + 55;
}
else {
hexed = sum + 48;
}
cout << hexed;
}
}
cout << endl;
}
};
int main() {
char ar[strng];
for (int i=0; i<strng; i++) {
if ((i+1) % 8 == 0) {
ar[i] = '0';
}
else {
ar[i] = '1';
}
}
BariBitKari arr(ar);
arr.print_hexa();
arr.print_deci();
return 0;
}
要将 128 位数字转换为“十进制”字符串,我将假设大十进制值只需要包含在一个字符串中,并且我们只是在“正数”中" space。在不使用适当的大数库的情况下,我将演示一种将任何字节数组转换为十进制字符串的方法。这不是最有效的方法,因为它会不断地解析、复制和扫描数字字符串。
我们将利用以下事实:
0x87654321 == 2,271,560,481
可以转换为以 8 位块移位的一系列字节。加回这些移位的块会得到原始值
0x87 << 24 == 0x87000000 == 2,264,924,160
0x65 << 16 == 0x00650000 == 6,619,136
0x43 << 8 == 0x00004300 == 17,152
0x21 << 0 == 0x00000021 == 33
Sum == 0x87654321 == 2,271,560,481
所以我们将 128 位数字转换为字符串的策略是:
将原始的 16 字节数组转换为 16 个字符串 - 每个字符串代表数组每个字节的十进制等效值
根据数组中原始字节的索引,将每个字符串“左移”适当的位数。利用左移相当于乘以2的事实
将所有这些移位的字符串加在一起
因此,为了实现这一点,我们引入了一个函数,可以将两个字符串(仅由数字组成)“相加”:
// s1 and s2 are string consisting of digits chars only ('0'..'9')
// This function will compute the "sum" for s1 and s2 as a string
string SumStringValues(const string& s1, const string& s2)
{
string result;
string str1=s1, str2=s2;
// make str2 the bigger string
if (str1.size() > str2.size())
{
swap(str1, str2);
}
// pad zeros onto the the front of str1 so it's the same size as str2
while (str1.size() < str2.size())
{
str1 = string("0") + str1;
}
// now do the addition operation as loop on these strings
size_t len = str1.size();
bool carry = false;
while (len)
{
len--;
int d1 = str1[len] - '0';
int d2 = str2[len] - '0';
int sum = d1 + d2 + (carry ? 1 : 0);
carry = (sum > 9);
if (carry)
{
sum -= 10;
}
result.push_back('0' + sum);
}
if (carry)
{
result.push_back('1');
}
std::reverse(result.begin(), result.end());
return result;
}
接下来,我们需要一个函数来对十进制字符串进行“左移”:
// s is a string of digits only (interpreted as decimal number)
// This function will "shift left" the string by N bits
// Basically "multiplying by 2" N times
string ShiftLeftString(const string& s, size_t N)
{
string result = s;
while (N > 0)
{
result = SumStringValues(result, result); // multiply by 2
N--;
}
return result;
}
然后把字节数组转成十进制字符串放在一起:
string MakeStringFromByteArray(unsigned char* data, size_t len)
{
string result = "0";
for (size_t i = 0; i < len; i++)
{
auto tmp = to_string((unsigned int)data[i]); // byte to decimal string
tmp = ShiftLeftString(tmp, (len - i - 1) * 8); // shift left
result = SumStringValues(result, tmp); // sum
}
return result;
}
现在让我们在上面使用的原始 32 位值上进行测试:
int main()
{
// 0x87654321
unsigned char data[4] = { 0x87,0x65,0x43,0x21 };
cout << MakeStringFromByteArray(data, 4) << endl;
return 0;
}
生成的程序将打印出来:2271560481
- 同上。
现在让我们在 16 字节的值上尝试一下:
int main()
{
// 0x87654321aabbccddeeff432124681111
unsigned char data[16] = { 0x87,0x65,0x43,0x21,0xaa,0xbb,0xcc,0xdd,0xee,0xff,0x43,0x21,0x24,0x68,0x11,0x11 };
std::cout << MakeStringFromByteArray(data, sizeof(data)) << endl;
return 0;
}
以上打印:179971563002487956319748178665913454865
我们将使用 python 来仔细检查我们的结果:
Python 3.8.3 (tags/v3.8.3:6f8c832, May 13 2020, 22:37:02) [MSC v.1924 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> int("0x87654321aabbccddeeff432124681111", 16)
179971563002487956319748178665913454865
>>>
我觉得不错。
我最初有一个实现可以在 32 位块而不是 8 位块中进行分块和求和。但是,涉及到小端与大端字节顺序问题。我将把潜在的优化作为改天的练习。