偽代碼如下:
string key("ZZZZZZZZZZZZZ"); //用字串存36進制
long long int tmp = 0;
int i = 0,k = 0;
for (i = key.length()-1; i>=0; i--) {
if (key[ i ] <- '9') {
k = key[ i ] - '0';
} else {
k = key[ i ] - 'A' + 10;
}
tmp = tmp*36 + k;
}
上面代碼存在一個問題就是36進制 string key("ZZZZZZZZZZZZZ"); 對于的十進制數字是 170581728179578200000,超過了long long int
的存盤范圍,tmp會溢位,有沒有好的方法解決這個問題,萬分感謝???
uj5u.com熱心網友回復:
十進制也可以用字串存啊
uj5u.com熱心網友回復:
如果tmp不溢位,先用tmp存,然后轉換為字串,但是不知道怎么跳過tmp,直接存字串
uj5u.com熱心網友回復:
有一個思路,就是找到36進制和10進制之間的對應關系,就像3位16進制可以完全轉成4位8進制一樣,然后一段一段的轉換、拼接uj5u.com熱心網友回復:
for (i = key.length()-1; i>=0; i--) {
if (key[ i ] <- '9') {
k = key[ i ] - '0';
} else {
k = key[ i ] - 'A' + 10;
}
tmp = tmp*36 + k;
}
現在看單個字符的轉換關系是這樣的,但是整體轉換是遞回先乘36載加尾數,并沒有一段一段的轉換規律
uj5u.com熱心網友回復:
if (key[ i ] <- '9') {什么是 -'9' ?
uj5u.com熱心網友回復:
哦,寫錯了是, if (key[ i ] <= '9')
uj5u.com熱心網友回復:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdbool.h>
#define _max(a, b) ((a) > (b) ? (a) : (b))
#define _min(a, b) ((a) > (b) ? (b) : (a))
#define _swap(l, r) \
do {\
typeof(l) __tmp = (l);\
(l) = (r);\
(r) = __tmp;\
} while (0)
#define assert_condition(cond, code) \
{\
if (!(cond)) {\
return (code);\
}\
}
static inline int _convert(int c) {
return isdigit(c) ? c - '0' : tolower(c) - 'a' + 10;
}
static char* reverse_str(char* str, int len) {
if (len < 2)
return str;
_swap(str[0], str[len - 1]);
reverse_str(str + 1, len - 2);
return str;
}
/* 單獨一位相加,回傳是否要進位 */
static inline bool _one_bit_add(char l, char r, bool flag, char* res) {
*res = l + r + (flag ? 1 : 0); /* flag: 進位標志 */
if (*res < '5' + '5') {
*res -= '0';
return false;
} else {
*res -= '0' + 10;
return true;
}
}
static char* _add(const char* l, const char* r) {
int l_len = strlen(l);
int r_len = strlen(r);
int shorter = _min(l_len, r_len);
int longer = _max(l_len, r_len);
bool flag = false;
const char* p = NULL;
char* res = (char*)calloc(1, longer + 2);
assert_condition(res != NULL, NULL);
/* 從個位開始相加,先將短串全部加到長串上,長串余下的位加0 */
for (int i = 0; i < shorter; ++i) {
flag = _one_bit_add(l[l_len - i - 1], r[r_len - i - 1], flag, &res[i]);
}
p = (l[shorter] ? l : r) + longer - shorter - 1;
for (int i = shorter; i < longer; ++i, --p) {
flag = _one_bit_add(*p, '0', flag, &res[i]);
}
/* 最高位進位 */
for (int i = longer; flag; ++i) {
flag = _one_bit_add('0', '0', flag, &res[i]);
}
/* 由于是從個位開始寫入,所以需要逆置結果,下面乘法同理 */
return reverse_str(res, strlen(res));
}
static char* _mul(const char* l, const char* r) {
int l_len = strlen(l);
int r_len = strlen(r);
/* 兩數相乘,結果長度是兩數長度之和 */
int res_len = l_len + r_len;
char* res = (char*)calloc(1, res_len + 1);
char* p = res; /* 用于移動賦值 */
int x = 0; /* 每次相乘一位的結果 */
for (int i = 0; i < res_len - 1 || x > 0; ++i, ++p) {
for (int j = 0; j <= i; ++j) {
int bit1 = l_len - i - 1 + j;
int bit2 = r_len - j - 1;
if (bit1 >= 0 && bit2 >= 0) {
x += (l[bit1] - '0') * (r[bit2] - '0');
}
}
*p = x % 10 + '0';
x /= 10;
}
/* 若結果為0,只顯示一個0 */
if (p > res && p[-1] == '0') {
res[1] = '\0';
}
return reverse_str(res, strlen(res));
}
static char* _pow(int base, int ex) {
char *res = (char*)calloc(1, 2);
res[0] = '1';
char base_str[64] = { 0 };
sprintf(base_str, "%d", base);
for (int i = 0; i < ex; ++i) {
char* tmp = _mul(res, base_str);
free(res);
res = tmp;
}
return res;
}
char* thirtySixToDeciaml(const char* src) {
char* dec = (char*)calloc(1, 2);
dec[0] = '0';
char digit[3] = { 0 };
int len = strlen(src);
for (int i = len; i > 0; --i) {
/* 使用字串相乘相加實作 dec += src[i-1] * pow(36, len-i) */
sprintf(digit, "%d", _convert(src[i - 1]));
char* power = _pow(36, len - i);
char* pro = _mul(digit, power);
char* tmp = _add(dec, pro);
free(power);
free(pro);
free(dec);
dec = tmp;
}
return dec;
}
int main(int argc, char* argv[]) {
if (argc != 2) {
fprintf(stderr, "Invalid argument!\n");
exit(1);
}
const char* src = argv[1];
char* res = thirtySixToDeciaml(src);
printf("%s\n", res);
free(res);
return 0;
}
用字串相乘相加來防溢位,理論上應該可以計算無限長度
uj5u.com熱心網友回復:
感謝,感謝,我先按照這個測驗看看
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/94430.html
標籤:C++ 語言
