📌 更新(2026-09-01):整理归档这篇旧文,顺手用 GCC 15.1.0 把整个库重新编译复测了一遍。不测不知道:pow 函数里藏着一个参数传反的 bug,而被注释掉的多参数运算一旦复活,在 -O2 优化下会当场段错误——2022 年它们全都”看起来没问题”。详见复盘两节。
2022 年 11 月的一个晚上,我又一次看到了那个经典画面:0.1 + 0.2 = 0.30000000000000004。浮点数这东西,平时看着人模狗样,一涉及精度就开始表演。刚学完结构体的我突发奇想:既然分数是精确的,为什么不自己写一个分数运算库?
于是有了这个文件夹——我的分数,主文件也叫 我的分数.c。对,起名的时候一点都没客气,这是我的分数,从头到脚都是我的。这个库后来搬进了 Mathematics-System 仓库的 Fraction/ 目录,和 Matrix、BigInterge 住在一起——数学三件套,聚齐了。
一、分数怎么表示
分数的核心数据结构简单到不能再简单:一个分子,一个分母。
1 2 3 4 5 6 7
| typedef long long ll;
typedef struct my_Fractional { ll Numerator; ll Denominator; }Fractional;
|
当年在这里埋了一颗雷:分子分母都用了 long long,可后面打印的时候用的是 %d。这颗雷先记着,复盘的时候再拆。
构造分数的 Fractional_init 立了三条规矩,缺一不可:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| void Fractional_init(ptr_Fractional Fractional,ll Numerator, ll Denominator) { if(Denominator == 0) { printf("error : 分母不能为0!"); exit(0); } else if(Denominator < 0) { Numerator = -Numerator; Denominator = -Denominator; } ll common_factor = gcd(Numerator, Denominator); Fractional->Numerator = Numerator / common_factor; Fractional->Denominator = Denominator / common_factor; }
|
分母为零直接 exit(0),简单粗暴;分母为负就把负号搬到分子上,保证分母永远为正(-1/2 和 1/-2 是同一个数,但打印出来前者体面得多);最后 gcd 约分,2/4 进来就得是 1/2 出去。gcd 本体是教科书式的递归:
1 2 3 4
| ll gcd(ll x, ll y) { return !y ? x : gcd(y, x % y); }
|
二、先把内存管起来
库里的运算函数全是”返回新分数”的设计,意味着每次运算都要 malloc。malloc 来 malloc 去,忘了 free 怎么办?当年的方案是:搞一个记账池。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| #define MAX_POOL_NUM 100 ptr_Fractional malloc_space[MAX_POOL_NUM];
void * my_malloc_temp(size_t _Size) { static int malloc_space_i = 0; if(malloc_space_i == 0) { for(int i = 0 ; i < MAX_POOL_NUM; ++i) { malloc_space[i] = NULL; } } ptr_Fractional result = (ptr_Fractional)malloc(_Size); malloc_space[malloc_space_i++] = result; return (void *)result; }
void my_free() { for(int i = 0 ; i < MAX_POOL_NUM; ++i) { if(malloc_space[i] != NULL) { free(malloc_space[i]); } } }
|
走 my_malloc_temp 申请的每一块都被记在账本上,程序收尾时 my_free() 一键放养,不用一块一块数。这个思路后来在大整数库里发扬光大成了哈希记账版,在数电帮你算里变成了虚结构体对象池加析构函数自动回收——血缘关系一清二楚:BigInterge 开发记、数电帮你算开发记。
但要坦白一个设计缺陷:库里其实有两个分配函数,my_malloc_temp 记账,my_malloc 是裸 malloc 的马甲。而相当一部分函数(包括下面的 float_to_Fractional、所有 _2 后缀的运算)走的是裸的那条路——也就是说 my_free() 根本收不回它们。账本只记了一半的账,属于”防盗门装了一扇,另一扇用胶带封了一下”。
三、四则运算
四个 _2 后缀的标准两元运算,思路都是”通分—算—约分”,比较有意思的是两个偷懒技巧。
减法不想单独写一套通分逻辑,于是”借了又还”:
1 2 3 4 5 6 7 8 9 10
| ptr_Fractional Fractional_sub_2(ptr_Fractional Fractional_1, ptr_Fractional Fractional_2) { Fractional temp; Fractional_opposite(Fractional_2); temp = *Fractional_2; Fractional_opposite(Fractional_2); return Fractional_add_2(Fractional_1,&temp); }
|
把第二个分数变成相反数,加一下,再变回来——减法就没了,只剩加法。注释里那句”相同类型的结构体可以这样赋值捏”是当年刚发现结构体可以直接赋值时的兴奋残留。
除法同理:除以一个数等于乘它的倒数,乘完记得把人家倒回来,别毁人清白:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| ptr_Fractional Fractional_div_2(ptr_Fractional Fractional_1, ptr_Fractional Fractional_2) { ptr_Fractional result = (ptr_Fractional)my_malloc(sizeof(Fractional)); ptr_Fractional temp;
temp = Fractional_reciprocal(Fractional_2); result = Fractional_mcl_2(Fractional_1, temp); Fractional_reciprocal(Fractional_2);
Fractional_init(result, result->Numerator, result->Denominator);
return result; }
|
顺带一提,取倒数内部用的是无临时变量的加减法交换:
1 2 3 4 5 6
| void exchang(ll *A, ll *B) { *A = *B - *A; *B = *B - *A; *A = *B + *A; }
|
(第一行 result malloc 完没用到就被覆盖了,这块内存悄悄漏掉了——池子反正也不记账,就当无事发生。)
四、变参全家桶
光会两个数相加还不够,Fractional_add(int n, ...) 可以一口气把 n 个分数加在一起:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| ptr_Fractional Fractional_add(int n, ...) { int i; va_list valist;
ptr_Fractional ptr_Fractional_temp = NULL; ptr_Fractional result = (ptr_Fractional)my_malloc(sizeof(Fractional)); Fractional result_temp;
result->Denominator = 1; result->Numerator = 0;
va_start(valist, n);
for(i = 0; i < n; i++) { ptr_Fractional_temp = va_arg(valist, ptr_Fractional); result = Fractional_add_2(ptr_Fractional_temp,result); result_temp.Denominator = result->Denominator; result_temp.Numerator = result->Numerator; free(result); result = &result_temp; }
va_end(valist); return result; }
|
变参函数的完整玩法在《变参函数及其应用》里单独展开,这里只看最后一行——result = &result_temp,把一个局部变量的地址当成了返回值。这行代码是本文最大的彩蛋,复盘见。
先说那段注释的乌龙:”下面主要就是要 free 掉内存,防止溢出”。想法是对的——Fractional_add_2 内部 malloc 的新结果确实需要释放,防止循环 n 次攒一屁股内存。但执行起来漏了另一半:free(result) 释放的是新结果,而上一轮的累加器 result(也是 malloc 来的)就这么被覆盖指针漏掉了。防溢出没防住, accumulator 倒是先漏为敬。
五、复盘一:返回栈变量的定时炸弹
先说结论:Fractional_add、Fractional_sub、Fractional_div 都把 result_temp 这个栈上局部变量的地址返回给了调用者。函数一返回,那块栈内存就还给系统了。
2022 年写下这段代码的时候,它在 Dev-C++ 里跑得好好的,注释掉的 main 里那几行测试全都输出了正确答案。2026 年我用 GCC 15.1 重新验证,为了不动原文件一个字节,用 -Dmain=orig_main 把原来的 main 挂起,另写驱动把注释掉的多参数运算全部复活:
1 2 3 4 5 6 7 8 9
| === GCC 15.1.0 -O0 === --- add(3, 1/10, 2/10, 15/10) --- 9/5 --- sub(3, 15/10 - 2/10 - 1/10) --- 6/5 --- div(3, 15/10 / 2/10 / 1/10) --- 75/1 --- pow(1/10, 2) --- 100/1
|
-O0 下四个答案,三个全对(9/5、6/5、75/1),跟四年前一模一样。是不是说明没毛病?把优化开到 -O2 再跑一遍:
1 2 3 4 5
| === GCC 15.1.0 -O2 逐项定位 === add -> Segmentation fault (exit=139) sub -> 6/5 div -> 75/1 pow -> 100/1
|
add 直接段错误。
为什么偏偏是 add?看返回路径就明白了:sub 和 div 循环里虽然也在玩 &result_temp,但它们的最后一步都落回了一个新 malloc 的堆内存(sub_2 内部的 add_2、div_2 的乘法结果),返回的是堆地址,安全。而 add 循环结束后直接 return result,返回的就是 &result_temp——一个已经寿终正寝的栈地址。-O0 下没人去动那块内存,数据还新鲜,读出来是对的;-O2 一优化,栈帧布局一变,那块内存被后续调用踩了个稀碎。
四年没出事不是因为没有 bug,是因为运气一直在线。
六、复盘二:pow 把参数传反了
-O0 那组输出里唯一不对的答案:(1/10)² = 100/1。分子分母,精确地倒了个个儿。
肇事者就一行:
1 2 3 4 5 6 7
| ptr_Fractional Fractional_pow(ptr_Fractional Fractional, int n) { Fractional->Denominator = long_integer_pow(Fractional->Denominator, n); Fractional->Numerator = long_integer_pow(Fractional->Numerator, n); Fractional_init(Fractional,Fractional->Denominator, Fractional->Numerator); return Fractional; }
|
前两行老老实实把分子分母各自乘方,第三行 Fractional_init 想做最后约分——结果第一个参数传了 Denominator,第二个传了 Numerator。init 的规矩是”第一个参数是分子”,于是约分完,分母坐在了分子的位置上。(1/10)² 先算成 1/100,约分时分子分母一换座,输出 100/1。
这个函数在当年的 main 里压根没被调用过,注释里没有,运行记录里也没有——它就这么带病潜伏了四年,直到这次复测才落网。这也算给”没用过的代码不等于没 bug 的代码”做了个活体标本。
七、循环小数转分数
库里的数学高光时刻:把 0.123123123… 这种循环小数精确转回分数。
数学原理初中就学过:设 x = 0.123123…,两边乘 1000 得 1000x = 123.123123…,相减 999x = 123,所以 x = 123/999。推广开:循环节有 c 位、循环前有 f 位小数的,x = (整数部分拼上循环节 − 非循环部分) / (10^(f+c) − 10^f)。
float_to_Fractional(double, ll circle_body) 就是这条公式的代码化:circle_body 是循环节(传 0 表示有限小数),先把小数点后九位数字逐位拆进数组,再从中找出循环节第一次出现的位置 float_front,最后套公式:
1 2 3
| int temp1 = data_float * pow_ten[float_front + circle_body_count]; int temp2 = data_float * pow_ten[float_front]; Fractional_init(result, temp1-temp2, pow_ten[float_front + circle_body_count] - pow_ten[float_front]);
|
文件夹里还有一个更原始的独立调试版 小数转分数.c,把每一步都打出来看(当年就是靠它对着的):
1 2 3 4 5 6 7 8
| 123123123 num : 123 count : 3 1 2 3 1 2 3 1 2 3 0 1 2 3 0 0 0 0 0 0 0 data_float: 0.123123 ciclr_count: 3 float_front : 0 123 - 0 123/999
|
九位数字数组 123123123 里从第 0 位就找到循环节 123,分子 123 − 0,分母 10³ − 10⁰ = 999,输出 123/999——注意这个调试版不做约分。同一个输入喂给库版,末尾多走一步 Fractional_init,得到约分后的:
库版 main 里另外两组实测:
1 2
| Fractional_print(float_to_Fractional(0.1123, 123),true); → 187/1665 Fractional_print(float_to_Fractional(0.12345, 0),true); → 2469/20000
|
0.1123 循环节 123,即 0.1(123) = (1123−1)/9990 = 187/1665;0.12345 是有限小数,走 10⁸ 缩放那条路,12345000/100000000 约分成 2469/20000。全部手算可验证。
(顺带记录调试版输出里一个时代细节:ciclr_count——cycle 拼错的考古现场,就让它留在那吧。另外这个文件的注释在多年的编码转换里阵亡了一部分,文末附的完整源码已把乱码注释整行删除,代码逻辑逐字未动。)
八、零碎但真实
%d 打 long long。开头埋的雷在这拆:Fractional_print 用 printf("%d/%d", ...) 打两个 ll。GCC 15 一编译就甩出两条警告:
1 2
| warning: format '%d' expects argument of type 'int', but argument 2 has type 'll' {aka 'long long int'} [-Wformat=]
|
现在数值小没露馅(小整数在寄存器低 32 位里碰巧是对的),哪天算出一个大分数就会当场表演输出错乱。属于典型的”埋雷一时爽”。
Fractional_calc 空壳。头文件式的函数声明区里端端正正写着 ptr_Fractional Fractional_calc(const char *, ...), visions 很大——一个类似 printf 格式串驱动的分数计算器。实现区里只有一行 ;。这个 TODO 一躺就是四年,本文也无意替它实现,留白也是一种纪念。
main 里那排注释。真正的 main 前面有整整十行被注释掉的旧实验——每一行都是当年的一次运行记录。旧代码舍不得删大概就是这个原因:那是这个库的成长日志。
九、完整源码
库本体(GBK 原件,转录为 UTF-8,内容逐字节未动):
我的分数.c1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505
| #include <stdio.h> #include <stdarg.h> #include <stdlib.h>
#define true 1 #define false 0 #define MAX_POOL_NUM 100
typedef long long ll;
typedef struct my_Fractional { ll Numerator; ll Denominator; }Fractional;
typedef struct my_Fractional* ptr_Fractional;
ptr_Fractional malloc_space[MAX_POOL_NUM];
void * my_malloc_temp(size_t _Size); void * my_malloc(size_t _Size); void my_free();
void exchang(ll *A, ll *B);
ll gcd(ll x, ll y); void Fractional_init(ptr_Fractional Fractional,ll Numerator, ll Denominator); void Fractional_print(ptr_Fractional Fractional, int flag);
ptr_Fractional Fractional_temp(ll Numerator, ll Denominator);
ptr_Fractional float_to_Fractional(double data_float, ll circle_body);
ptr_Fractional Fractional_opposite(ptr_Fractional Fractional); ptr_Fractional Fractional_reciprocal(ptr_Fractional Fractional);
ptr_Fractional Fractional_add_2(ptr_Fractional Fractional_1, ptr_Fractional Fractional_2); ptr_Fractional Fractional_add(int n, ...);
ptr_Fractional Fractional_sub_2(ptr_Fractional Fractional_1, ptr_Fractional Fractional_2); ptr_Fractional Fractional_sub(int n, ...);
ptr_Fractional Fractional_mcl_2(ptr_Fractional Fractional_1, ptr_Fractional Fractional_2); ptr_Fractional Fractional_mcl(int n, ...);
ptr_Fractional Fractional_div_2(ptr_Fractional Fractional_1, ptr_Fractional Fractional_2); ptr_Fractional Fractional_div(int n, ...);
ll long_integer_pow(ll x, int n); ptr_Fractional Fractional_pow(ptr_Fractional Fractional,int n);
ptr_Fractional Fractional_calc(const char *, ... );
int main() { Fractional_print(float_to_Fractional(0.1123, 123),true); Fractional_print(float_to_Fractional(0.12345, 0),true); my_free(); return 0; }
void * my_malloc_temp(size_t _Size) { static int malloc_space_i = 0; if(malloc_space_i == 0) { for(int i = 0 ; i < MAX_POOL_NUM; ++i) { malloc_space[i] = NULL; } } ptr_Fractional result = (ptr_Fractional)malloc(_Size); malloc_space[malloc_space_i++] = result; return (void *)result; }
void * my_malloc(size_t _Size) { return malloc(_Size); }
void my_free() { for(int i = 0 ; i < MAX_POOL_NUM; ++i) { if(malloc_space[i] != NULL) { free(malloc_space[i]); } } }
ll gcd(ll x, ll y) { return !y ? x : gcd(y, x % y); }
void Fractional_init(ptr_Fractional Fractional,ll Numerator, ll Denominator) { if(Denominator == 0) { printf("error : 分母不能为0!"); exit(0); } else if(Denominator < 0) { Numerator = -Numerator; Denominator = -Denominator; } ll common_factor = gcd(Numerator, Denominator); Fractional->Numerator = Numerator / common_factor; Fractional->Denominator = Denominator / common_factor; }
void Fractional_print(ptr_Fractional Fractional, int flag) { printf("%d/%d",Fractional->Numerator,Fractional->Denominator); if(flag) { putchar('\n'); } }
ptr_Fractional Fractional_temp(ll Numerator, ll Denominator) { ptr_Fractional result = (ptr_Fractional)my_malloc_temp(sizeof(Fractional)); result->Numerator = Numerator; result->Denominator = Denominator; return result; }
void exchang(ll *A, ll *B) { *A = *B - *A; *B = *B - *A; *A = *B + *A; }
ptr_Fractional float_to_Fractional(double data_float, ll circle_body) { const static int pow_ten[] = {1,10,100,1000,10000,100000,1000000,10000000,100000000, 1000000000}; ptr_Fractional result = (ptr_Fractional)my_malloc(sizeof(Fractional)); if( circle_body < 0) { exit(0); }
if( !circle_body ) { ll num = 100000000; Fractional_init(result, (ll)(data_float * num), num); } else { int circle_body_count = 0; int float_front; ll circle_body_temp = circle_body;
ll temp = data_float * 1000000000;
while(circle_body_temp) { circle_body_temp /= 10; circle_body_count++; }
char float_num[10] = {0}; char circle_num[10] = {0}; int i = 0;
for(int j = circle_body_count - 1; j >= 0; j--) { circle_num[i++] = (circle_body / pow_ten[j]) % 10; } i = 0; for(int j = 8; j >= 0; j--) { float_num[i++] = (temp / pow_ten[j]) % 10; }
char flag = false; float_front = 0; for(int j = 0; j < 10; ++j) { if(float_num[j] == circle_num[0] && flag == false) { flag = true; }
if( flag ) { char flag_circle = true; int circle_num_i = 0; for(int k = j; k < j + circle_body_count; k++) { if(float_num[k] != circle_num[circle_num_i++]) { flag_circle = false; } } if( flag_circle ) { float_front = j; break; } else { flag = false; } } }
int temp1 = data_float * pow_ten[float_front + circle_body_count]; int temp2 = data_float * pow_ten[float_front]; Fractional_init(result, temp1-temp2, pow_ten[float_front + circle_body_count] - pow_ten[float_front]); } return result; }
ptr_Fractional Fractional_opposite(ptr_Fractional Fractional) { Fractional->Numerator = -Fractional->Numerator; return Fractional; }
ptr_Fractional Fractional_reciprocal(ptr_Fractional Fractional) { if(Fractional->Numerator < 0) { Fractional->Numerator = -Fractional->Numerator; Fractional->Denominator = -Fractional->Denominator; } exchang(&(Fractional->Numerator),&(Fractional->Denominator)); return Fractional; }
ptr_Fractional Fractional_add_2(ptr_Fractional Fractional_1, ptr_Fractional Fractional_2) { ptr_Fractional result = (ptr_Fractional)my_malloc(sizeof(Fractional));
ll Denominator_New = Fractional_1->Denominator * Fractional_2->Denominator; ll Numerator_New = Fractional_1->Denominator * Fractional_2->Numerator + Fractional_2->Denominator * Fractional_1->Numerator; ll common_factor = gcd(Numerator_New, Denominator_New); result->Numerator = Numerator_New / common_factor; result->Denominator = Denominator_New / common_factor;
return result; }
ptr_Fractional Fractional_add(int n, ...) { int i; va_list valist;
ptr_Fractional ptr_Fractional_temp = NULL; ptr_Fractional result = (ptr_Fractional)my_malloc(sizeof(Fractional)); Fractional result_temp;
result->Denominator = 1; result->Numerator = 0;
va_start(valist, n);
for(i = 0; i < n; i++) { ptr_Fractional_temp = va_arg(valist, ptr_Fractional); result = Fractional_add_2(ptr_Fractional_temp,result); result_temp.Denominator = result->Denominator; result_temp.Numerator = result->Numerator; free(result); result = &result_temp; }
va_end(valist); return result; }
ptr_Fractional Fractional_sub_2(ptr_Fractional Fractional_1, ptr_Fractional Fractional_2) { Fractional temp; Fractional_opposite(Fractional_2); temp = *Fractional_2; Fractional_opposite(Fractional_2); return Fractional_add_2(Fractional_1,&temp); }
ptr_Fractional Fractional_sub(int n, ...) { int i; va_list valist;
ptr_Fractional ptr_Fractional_temp = NULL; ptr_Fractional first; ptr_Fractional result = (ptr_Fractional)my_malloc(sizeof(Fractional)); Fractional result_temp;
va_start(valist, n);
first = va_arg(valist, ptr_Fractional);
result->Numerator = 0; result->Denominator = 1; for(i = 1; i < n; i++) { ptr_Fractional_temp = va_arg(valist, ptr_Fractional); result = Fractional_add_2(result,ptr_Fractional_temp); result_temp.Denominator = result->Denominator; result_temp.Numerator = result->Numerator; free(result); result = &result_temp; } result = Fractional_sub_2(first,result); va_end(valist); return result; }
ptr_Fractional Fractional_mcl_2(ptr_Fractional Fractional_1, ptr_Fractional Fractional_2) { ptr_Fractional result = (ptr_Fractional)my_malloc(sizeof(Fractional));
ll Denominator_New = Fractional_1->Denominator * Fractional_2->Denominator; ll Numerator_New = Fractional_1->Numerator * Fractional_2->Numerator; Fractional_init(result, Numerator_New, Denominator_New);
return result; }
ptr_Fractional Fractional_mcl(int n, ...) { int i; va_list valist;
ptr_Fractional ptr_Fractional_temp = NULL; ptr_Fractional result = (ptr_Fractional)my_malloc(sizeof(Fractional)); Fractional result_temp;
result->Denominator = 1; result->Numerator = 1;
va_start(valist, n);
for(i = 0; i < n; i++) { ptr_Fractional_temp = va_arg(valist, ptr_Fractional); result = Fractional_mcl_2(ptr_Fractional_temp,result); result_temp.Denominator = result->Denominator; result_temp.Numerator = result->Numerator; free(result); result = &result_temp; }
va_end(valist); return result; }
ptr_Fractional Fractional_div_2(ptr_Fractional Fractional_1, ptr_Fractional Fractional_2) { ptr_Fractional result = (ptr_Fractional)my_malloc(sizeof(Fractional)); ptr_Fractional temp;
temp = Fractional_reciprocal(Fractional_2); result = Fractional_mcl_2(Fractional_1, temp); Fractional_reciprocal(Fractional_2); Fractional_init(result, result->Numerator, result->Denominator);
return result; } ptr_Fractional Fractional_div(int n, ...) { int i; va_list valist;
ptr_Fractional ptr_Fractional_temp = NULL; ptr_Fractional result = (ptr_Fractional)my_malloc(sizeof(Fractional)); Fractional result_temp;
va_start(valist, n); if(n < 1) { return NULL; } else if(n == 1) { return va_arg(valist, ptr_Fractional); } ptr_Fractional ptr_Fractional_first = va_arg(valist, ptr_Fractional); ptr_Fractional ptr_Fractional_second = va_arg(valist, ptr_Fractional); result = Fractional_div_2(ptr_Fractional_first,ptr_Fractional_second); for(i = 2; i < n; i++) { ptr_Fractional_temp = va_arg(valist, ptr_Fractional); result = Fractional_div_2(result, ptr_Fractional_temp); result_temp.Denominator = result->Denominator; result_temp.Numerator = result->Numerator; free(result); result = &result_temp; }
va_end(valist); return result; }
ll long_integer_pow(ll x, int n) { ll r = 1; while (n--) { r *= x; } return r; }
ptr_Fractional Fractional_pow(ptr_Fractional Fractional, int n) { Fractional->Denominator = long_integer_pow(Fractional->Denominator, n); Fractional->Numerator = long_integer_pow(Fractional->Numerator, n); Fractional_init(Fractional,Fractional->Denominator, Fractional->Numerator); return Fractional; }
ptr_Fractional Fractional_calc(const char * str, ... ) { ; }
|
独立调试版 小数转分数.c(乱码注释已整行删除,代码逻辑逐字未动):
小数转分数.c1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
| #include <stdio.h>
#define true 1 #define false 0 typedef long int ll; void float_to_Fractional(double data_float, ll circle_body);
int main() { float_to_Fractional(0.123123123,123); return 0; }
void float_to_Fractional(double data_float, ll circle_body) { const static int pow_ten[] = {1,10,100,1000,10000,100000,1000000,10000000,100000000, 1000000000}; int circle_body_count = 0; int float_front; ll circle_body_temp = circle_body;
ll temp = data_float * 1000000000; printf("%ld\n",temp);
while(circle_body_temp) { circle_body_temp /= 10; circle_body_count++; }
char float_num[10] = {0}; char circle_num[10] = {0}; int i = 0; printf("num : %ld count : %d\n",circle_body, circle_body_count); for(int j = circle_body_count - 1; j >= 0; j--) { circle_num[i++] = (circle_body / pow_ten[j]) % 10; } i = 0; for(int j = 8; j >= 0; j--) { float_num[i++] = (temp / pow_ten[j]) % 10; }
i = 0; while(i < 10) { printf("%d ",float_num[i++]); } printf("\n"); i = 0; while(i < 10) { printf("%d ",circle_num[i++]); } printf("\n");
char flag = false; float_front = 0; for(int j = 0; j < 10; ++j) { if(float_num[j] == circle_num[0] && flag == false) { flag = true; }
if( flag ) { char flag_circle = true; int circle_num_i = 0; for(int k = j; k < j + circle_body_count; k++) { if(float_num[k] != circle_num[circle_num_i++]) { flag_circle = false; } } if( flag_circle ) { float_front = j; break; } else { flag = false; } } } printf("data_float: %f ciclr_count: %d\n", data_float, circle_body_count); printf("float_front : %d\n", float_front);
int temp1 = data_float * pow_ten[float_front + circle_body_count]; int temp2 = data_float * pow_ten[float_front]; printf("%d - %d\n",temp1, temp2);
printf("%d/%d\n", temp1-temp2 ,pow_ten[float_front + circle_body_count] - pow_ten[float_front]); }
|
分数这东西,浮点数时代看着笨,但它精确、诚实、从不含糊——这一点,值得用 505 行 C 代码致敬。