[英]Create a precise atof() implementation in c
我已經用 c 編寫了一個 atof() 實現。 我在這個實現中面臨四舍五入的錯誤。 因此,輸入 1236.965 的測試值給出 1236.964966 的結果,但庫 atof() 函數返回 1236.965000 。 我的問題是,如何使用戶定義的 atof() 實現更“正確”?
可以在某處找到 atof() 的庫定義嗎?
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
float str_to_float(char *);
void float_to_str(float,char *);
int main(){
int max_size;
float x;
char *arr;
printf("Enter max size of string : ");
scanf("%d",&max_size);
arr=malloc((max_size+1)*sizeof(char));
scanf("%s",arr);
x=str_to_float(arr);
printf("%f\n%f",x,atof(arr));
return 0;
}
float str_to_float(char *arr){
int i,j,flag;
float val;
char c;
i=0;
j=0;
val=0;
flag=0;
while ((c = *(arr+i))!='\0'){
// if ((c<'0')||(c>'9')) return 0;
if (c!='.'){
val =(val*10)+(c-'0');
if (flag == 1){
--j;
}
}
if (c=='.'){ if (flag == 1) return 0; flag=1;}
++i;
}
val = val*pow(10,j);
return val;
}
將所有花車改為雙打。 當我測試它時,它給出了與測試用例的庫函數atof
相同的結果。
atof
返回雙倍,而不是浮點數。 請記住,它實際上是 double 而不是 C 中“正常”浮點類型的 float。浮點文字,例如3.14
,屬於 double 類型,而庫函數例如sin
、 log
和(可能具有欺騙性命名) atof
與雙打一起工作。
盡管如此,它仍然不會是“精確的”。 作為浮點數,最接近 1236.965 的是(正好)1236.9649658203125,作為雙精度數 1236.9649999999999181454768404364585873046484375,將 6 printf 舍入到 6 printf 到 9。 無論二進制浮點數有多少位,1236.965 都無法精確表示,類似於 1/3 無法用有限數量的十進制數字精確表示:0.3333333333333333...
而且,正如在評論中的討論中所見,這是一個難題,如果您希望代碼始終提供最接近的值,則可能存在許多陷阱。
如何使用戶定義的 atof() 實現更“正確”?
簡單:1) 從不溢出中間計算和 2) 只循環一次(最后)。
很難做到這兩個步驟。
注意:C 的atof()
、 strtof()
等也處理指數表示法 - 十進制和十六進制。
潛在的四舍五入
val*10
(val*10)+(c-'0');
pow(10,j)
val*pow(10,j) // This last multiplication is the only tolerable one.
潛在的溢出(即使最終答案在范圍內)
val*10
(val*10)+(c-'0');
pow(10,j)
使用像double
這樣更寬的類型可以大大減少此類問題的發生,並實現 OP 的“更'正確'”。 然而它們仍然存在。
要從所有字符串輸入中獲得最佳(正確)浮點結果,這不是一個容易解決的問題。
解決的示例方法。
避免溢出:而不是pow(10,j)
:
val = val*pow(5,j); // rounds, `pow(5,j)` not expected to overflow a finite final result.
val = val*pow(2,j); // Does not round except at extremes
代碼應在循環中使用擴展整數數學形成(ival*10)+(c-'0')
以確保准確性。
然而,這只是許多極端案例的皮毛。
@Eric Postpischil評論了一個健壯的 C++ 代碼,它可以很好地處理非指數符號字符串輸入。 它使用整數進行初始數學運算,並且僅在此過程的后期進行舍入。 除非您的代表超過 10,000,因為問題已被刪除,否則此鏈接代碼是不可見的。
我用你的代碼作為靈感來寫我自己的。 其他評論者和答案沒有認識到問題的最初原因是嵌入的情況。 在我的情況下,庫“atof”引入了一些做“printf”的東西,它引入了我沒有的“系統調用”。
所以....在這里我提出了一個簡單的(不實現指數表示法)atof 實現,它適用於浮點數,適用於嵌入。
我的實現使用更少的變量。
float ratof(char *arr)
{
float val = 0;
int afterdot=0;
float scale=1;
int neg = 0;
if (*arr == '-') {
arr++;
neg = 1;
}
while (*arr) {
if (afterdot) {
scale = scale/10;
val = val + (*arr-'0')*scale;
} else {
if (*arr == '.')
afterdot++;
else
val = val * 10.0 + (*arr - '0');
}
arr++;
}
if(neg) return -val;
else return val;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.