2016-10-31 7 views
2

strtolは、入力された文字列strを指定された2〜36の任意の基数のlong値に変換します。strtof()は同様の機能を提供しますが、 strtofと同じ機能を持ちますが、ベースを選択することはできますか?Cのstrtol()に相当する浮動小数点

たとえば、文字列として101.101が入力されたとします。私は

strtof("101.101", null, 2); 

を行うと、あなたは.でそれを分割し、10進数の後に前の部分と一部を変換する文字列を解析することができます5.625.

+0

変換する浮動小数点値の例を表示できますか? –

+0

'。'の前後の部分を単純に変換することができます。 strtolを使って両方の浮動小数点数を浮動小数点数にする –

+0

@ ZachPそれは小数点の前の数字に対して機能しますが、その後はどうなりますか? –

答えて

1

の出力を得ることができるようにしたいです。その後、その文字列から浮動小数点数を作成することができます。これを実現する簡単な関数があります。

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です。

+0

101.1101は5.8125でなければならないが、5.13を出すだろうか?バイナリ分数の表現はどのようなものか、サンプル中の小数部分をどのように得るか –

+0

小数部分の先頭の0はどのように扱いますか? –

+0

@ KarstenKoopあなたはそれについて正しいです、小数部分を世話するでしょう。しかし、先行する0を扱うことについてどういう意味ですか?それはどこで問題を引き起こすでしょうか? –

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; 
} 

(Iが負の数の取り扱いを残していることに注意してください。)

あなたはそれを持っていると、それは、小数点を検出し、同様にそれの右側に数字を処理するために簡単です:

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数値的により良い行儀される可能性がありますyのあまり目立たないアプローチは、次のとおりです。

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; 
} 

私は予想通り

123 
21 
123.123000 
5.625000 
123.123000 
5.625000 

を印刷し

#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; 
} 

でこれらをテストしました。

もう一つ注意:これらの関数は拠点を処理しないFPと10を超える

0

計算は、エラーやその他の機微オフ蓄積ラウンドを被ることができます。以下では、単純に整数部分と小数部分を2つの基数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 

上記2つの部分はlongの範囲を超えてはならないという点で制限されています。コードは、より制限の少ない機能のために、intmax_tのようなより広いタイプを使用することができる。

関連する問題