strtol
將輸入的字符串str轉換爲任意指定的2至36的鹼基的長整型值。strtof()
提供了類似的功能,但不允許指定基數。是否有另一個功能與strtof
相同,但允許您選擇基地?相當於C中strtol()的浮點數
例如假設101.101作爲字符串輸入。我希望能夠做
strtof("101.101", null, 2);
,並得到5.625.
strtol
將輸入的字符串str轉換爲任意指定的2至36的鹼基的長整型值。strtof()
提供了類似的功能,但不允許指定基數。是否有另一個功能與strtof
相同,但允許您選擇基地?相當於C中strtol()的浮點數
例如假設101.101作爲字符串輸入。我希望能夠做
strtof("101.101", null, 2);
,並得到5.625.
輸出可以解析字符串給它的.
分裂和小數點後和部分之前轉換的部分。之後,您可以創建一個浮動字符串。這是一個簡單的功能,可以實現這一點。
float new_strtof(char* const ostr, char** endptr, unsigned char base)
{
char* str = (char*)malloc(strlen(ostr) + 1);
strcpy(str, ostr);
const char* dot = ".";
/* I do not validate any input here, nor do I do anything with endptr */ //Let's assume input of 101.1101, null, 2 (binary)
char *cbefore_the_dot = strtok(str, dot); //Will be 101
char *cafter_the_dot = strtok(NULL, dot); //Will be 0101
float f = (float)strtol (cbefore_the_dot, 0, base); //Base would be 2 = binary. This would be 101 in decimal which is 5
int i, sign = (str[0] == '-'? -1 : 1);
char n[2] = { 0 }; //will be just for a digit at a time
for(i = 0 ; cafter_the_dot[i] ; i++) //iterating the fraction string
{
n[0] = cafter_the_dot[i];
f += strtol(n, 0, base) * pow(base, -(i + 1)) * sign; //converting the fraction part
}
free(str);
return f;
}
人們可以用更高效,更不髒的方式來管理這個,但這只是一個例子來向你展示這個背後的想法。以上這些對我來說很好。
不要忘了#include <math.h>
並編譯-lm
標誌。一個例子是gcc file.c -o file -lm
。
101.1101應該是5.8125,但你會走出5.13,對吧?也許你可以更清楚一點,二進制分數的表示是什麼,以及如何從樣本中得到小數部分 –
以及如何處理小數部分的前導0? –
@KarstenKoop你是對的,會照顧小數部分。但是,對於處理領先的0,你的意思是什麼?它會在哪裏引起問題? –
爲了便於比較,這裏有atoi()
簡單,直接的版本,接受一個任意基地使用(即不一定是10):
#include <ctype.h>
int myatoi(const char *str, int b)
{
const char *p;
int ret = 0;
for(p = str; *p != '\0' && isspace(*p); p++)
;
for(; *p != '\0' && isdigit(*p); p++)
ret = b * ret + (*p - '0');
return ret;
}
(請注意,我已經離開了負數處理)
一旦你得到了,這是簡單的檢測小數點和處理數字到它的右邊還有:
double myatof(const char *str, int b)
{
const char *p;
double ret = 0;
for(p = str; *p != '\0' && isspace(*p); p++)
;
for(; *p != '\0' && isdigit(*p); p++)
ret = b * ret + (*p - '0');
if(*p == '.')
{
double fac = b;
for(p++; *p != '\0' && isdigit(*p); p++)
{
ret += (*p - '0')/fac;
fac *= b;
}
}
return ret;
}
一個slightl Ÿ不太明顯的方式,這可能會更好地表現數值是:
double myatof2(const char *str, int b)
{
const char *p;
long int n = 0;
double denom = 1;
for(p = str; *p != '\0' && isspace(*p); p++)
;
for(; *p != '\0' && isdigit(*p); p++)
n = b * n + (*p - '0');
if(*p == '.')
{
for(p++; *p != '\0' && isdigit(*p); p++)
{
n = b * n + (*p - '0');
denom *= b;
}
}
return n/denom;
}
我
#include <stdio.h>
int main()
{
printf("%d\n", myatoi("123", 10));
printf("%d\n", myatoi("10101", 2));
printf("%f\n", myatof("123.123", 10));
printf("%f\n", myatof("101.101", 2));
printf("%f\n", myatof2("123.123", 10));
printf("%f\n", myatof2("101.101", 2));
return 0;
}
預期它打印
123
21
123.123000
5.625000
123.123000
5.625000
測試了這些。
還要說明一點:這些功能不處理基地超過10
計算與FP可能招致累積舍入誤差等細微之處更大。下面簡單地計算整數部分和小數部分爲2個base-n整數,然後用最小FP計算得出答案。
代碼還需要應付負整數部分,並確保小數部分用相同的符號處理。
#include <ctype.h>
#include <math.h>
#include <stdlib.h>
double CC_strtod(const char *s, char **endptr, int base) {
char *end;
if (endptr == NULL) endptr = &end;
long ipart = strtol(s, endptr, base);
if ((*endptr)[0] == '.') {
(*endptr)++;
char *fpart_start = *endptr;
// Insure `strtol()` is not fooled by a space, + or -
if (!isspace((unsigned char) *fpart_start) &&
*fpart_start != '-' && *fpart_start != '+') {
long fpart = strtol(fpart_start, endptr, base);
if (ipart < 0) fpart = -fpart;
return fma(fpart, pow(base, fpart_start - *endptr), ipart);
}
}
return ipart;
}
int main() {
printf("%e\n", CC_strtod("101.101", NULL, 2));
}
輸出
5.625000e+00
上述被限制在這兩個部分不應該超過的long
的範圍內。代碼可以使用更廣泛的類型,如intmax_t
用於限制較少的功能。
你能展示一個浮點值轉換的例子嗎? –
您可以簡單地在'。'之前和之後轉換零件。使用strtol,然後使兩者浮動 –
@ZachP這對小數點前的數字起作用,但數字之後的數字是什麼? –