$ 1 - \frac{1}{2} + \frac{1}{3} -\frac{1}{4} + \cdots + \frac{1}{99} - \frac{1}{100} $
的C语言程序的解法及其相关的问题
一、C语言 定义浮点数类型解法(double类型)
#include<stdio.h>
#include<stdio.h>
int main(){
double result = 1.0; //定义result存储程序执行的结果
int iter = 2;
while(iter <= 100){
if(iter % 2 == 0){
result = result - 1/(double)iter; //当iter为偶数时,result 减 1 / iter
}else{
result = result + 1/(double)iter; //当iter为奇数时,result 加 1 / iter
}
iter++;
}
printf("1 - 1/2 + 1/3 - 1/4 + ... + 1/99 -1/100 = %f\n",result);
return 0;
}
计算结果 0.688172
二、C语言 定义分数结构体解法
#include <stdio.h>
typedef struct{ //定义分数结构体
long int numerator; //分子
long int denominator; //分母
}Fraction;
long int gcd(long int a,long int b){ //辗转相除法求最大公因数
while(b != 0){
long int temp = b;
b = a % b;
a = temp;
}
return a;
}
Fraction simplify(Fraction f){ //分数化简
long int common_divisor = gcd(f.numerator,f.denominator);
f.numerator /= common_divisor;
f.denominator /= common_divisor;
if(f.denominator < 0){
f.denominator = -f.denominator;
f.numerator = -f.numerator;
}
return f;
}
Fraction add(Fraction f1,Fraction f2){ //加法
Fraction result;
result.numerator = f1.numerator * f2.denominator + f2.numerator * f1.denominator;
result.denominator = f1.denominator * f2.denominator;
return simplify(result);
}
Fraction subtract(Fraction f1,Fraction f2){ //减法
Fraction result;
result.numerator = f1.numerator * f2.denominator - f2.numerator * f1.denominator;
result.denominator = f1.denominator * f2.denominator;
return simplify(result);
}
Fraction multiply(Fraction f1,Fraction f2){ //乘法
Fraction result;
result.numerator = f1.numerator * f2.numerator;
result.denominator = f1.denominator * f2.denominator;
return simplify(result);
}
Fraction divide(Fraction f1,Fraction f2){ //除法
Fraction result;
result.numerator = f1.numerator * f2.denominator;
result.denominator = f1.denominator * f2.numerator;
return result;
}
void printFraction(Fraction f){ //打印分数
if(f.denominator == 1){
printf("%ld\n",f.numerator);
}else{
printf("%ld/%ld\n",f.numerator,f.denominator);
}
}
int main(){
Fraction f1 = {2,3};
Fraction f2 = {3,4};
Fraction sum = add(f1,f2);
Fraction difference = subtract(f1,f2);
Fraction product = multiply(f1,f2);
Fraction quotient = divide(f1,f2);
printf("Sum = ");
printFraction(sum);
printf("Difference = ");
printFraction(difference);
printf("Product = ");
printFraction(product);
printf("Quotient = ");
printFraction(quotient);
//测试一下分数结构体的定义和相关函数是否正确
Fraction xsum = {1,1};
long int iter = 2;
while(iter <= 100){
Fraction x = {1,iter};
if(iter % 2 == 0){
xsum = subtract(xsum,x);
}else{
xsum = add(xsum,x);
}
iter = iter + 1;
}
printf("Xsum = "); //int类型定义的Fraction,计算这个问题数字上溢出
printFraction(xsum);
return 0;
}
int
类型定义的Fraction计算机结果是$ \frac{70732297}{385373376}$
,对应的小数0.18354225124259752
,显然int
类型定义Fraction
计算过程中整数出现了上溢- 该换用
long int
类型定义Fraction
计算结果是$\frac{1165334734037754711}{2019692938525864768}$
对应的小数值是0.5769860912066713
,long int
类型定义Fraction
精度仍然不足,整数计算出现了上溢 - 改用
long long int
类型,计算的结果为$ \frac{1165334734037754711}{2019692938525864768}$
,和用long int
类型定义的结果相同; - 上述用
int
、long int
、long long int
定义的结果都没用达到或者接近第一种方法用浮点数计算的结果 - 电脑操作系统是64位
Windows11
系统,int
类型占32位,long int
和long long int
类型都占64位(long long int
类型的规定可能大于long int
类型所占的字节数多。但实际上,由于系统的限制long long int
类型和long int
类型占用的字节数一要多)
三、Python自带的分数库计算
from fractions import Fraction
xsum = Fraction(1, 1)
for i in range(2, 101):
x = Fraction(1, i)
if i % 2 == 0:
xsum = xsum - x
else:
xsum = xsum + x
print(xsum)
print(float(xsum))
-
打印的结果是
$sum = \frac{47979622564155786918478609039662898122617}{69720375229712477164533808935312303556800}$
,对应的小数值0.6881721793101953
-
方法三和方法一结算的结果近似,而且能够提供结果的分数形式。但对于分数结果分子分母的大小已经远远超过64位整数的表示范围。对于C语言定义分数结构体的方式进行计算,需要超过64位的整数类型。
-
Python的分数库所能计算的精度要大于C语言默认类型定义Fraction结构体所能计算的精度
总结
- 用C语言编写代码要注意不同数据类型所能代表的数字大小,防止产生整数溢出和浮点数的上溢和下溢,适当情况下要考虑使用数组表示长整数和使用外部库;
- 需要高精度计算,可以考虑Python的高精度数学库,相比使用C语言,Python的库使用起来更方便
- 使用C语言编写代码时,要注意不同的数据类型表示数字的大小,有时候,
long int
和long long int
、double
和long double
表示的数字范围相同。