【代码】C语言|保留小数点后n位并四舍五入,便于处理运算和存储不善的浮点数

前言

有个人跟我说浮点数运算起来非常麻烦,总是算着算着丢失精度,导致计算结果取int的时候取不准。毕竟系统也没有自动根据这个数的精度四舍五入的功能。
比如int(2.999999999999999)=2,但是float(2.999999999999999)=3.000000。

我觉得这个问题很好解决,正好网上一搜这个问题的答主并没有给出完整且正常的代码,只提到了可以用“round”处理,或者自己手搓了一个round,让我震撼。所以我就简单写了一下这篇博客。

小数点后n位取整的思路

思路1 利用round

思路实现
  1. round这个函数在这个问题里的作用:round只能对小数点后面那一位做四舍五入,没办法舍入第n位。但是我们可以利用这个特性去做。
  2. 直观的思路简述:int(float(val,n),10),意思是取n位小数的val的值,然后转成int,从而完成满足n精度要求的int整型转换。

代码我让gpt给我写了一下:

在这里插入图片描述

可用的代码如下:

#include <stdio.h>
#include <math.h>

double roundToNDecimalPlaces(double num, int n) {
    double factor = pow(10, n);
    return round(num * factor) / factor;
}

int main() {
    double num = 9.99999999;
    int n = 3;
    double result = roundToNDecimalPlaces(num, n);
    printf("Result: %.3f\n", result);
    return 0;
}

编译方式(需要通过在编译命令中添加 -lm 选项来链接数学库):

gcc test_round.c -o test_round -lm

运行结果就是Result: 10.000

当然,你如果希望简洁一点,也可以把代码写成:int(round(val*pow(10,n)/pow(10,n)))

思路的优势和问题

优势:能实现n位存储精度。
问题:pow的数值过大的时候会超过double的有效数字表示能力。很多时候pow(10,5)就会溢出了。

思路2 利用字符串相关函数处理

思路实现

思路2这个思路比较清奇,是我随便想的。

  1. 思路来源:字符串可以做截断;
  2. 思路简述:int(str(float(vv)),10),就是利用sprintf的功能先转成str,然后取str的那几位再int向下取整。

照旧是让GPT写的,提问过程就不截图了,具体代码如下:

#include <stdio.h>
#include <stdlib.h>

double roundToNDecimalPlaces(double num, int n) {
    char format[20];
    sprintf(format, "%%.%df", n); // 构造格式字符串,保留n位小数
    char str[50];
    sprintf(str, format, num); // 将浮点数转换为字符串
    return atof(str); // 将字符串转换回浮点数
}

int main() {
    double num = 9.99999999;
    int n = 3;
    double result = roundToNDecimalPlaces(num, n);
    printf("Result: %.3f\n", result);
    return 0;
}

运行结果就是Result: 10.000

思路优势和问题

优势:能充分利用现有的计算机制,并且能够达到任意高的存储精度要求。
缺点:有的实现里面可能无法调用sprintf这个函数,并且sprintf这个函数运算速度不是很快。

思路3 利用float降低精度

思路实现

思路3是脱胎于思路1的。

  1. 思路核心:float的精度比double低
  2. 思路简述:int(float(val))。就是先把double类型的val数据强制转换为float给它丢失一下精度,然后再转int。这个实现思路只能保证float这么大的精度大小。

实现代码:

#include <stdio.h>

int roundToFloat(double num) {
    return (int)(float)num;
}

int main() {
    double num = 9.9999999;
    float temp = (float)num;
    int result = roundToFloat(num);
    printf("Temp: %f, Result: %d\n", temp, result);
    return 0;
}

运行结果:Temp: 10.000000, Result: 10

思路优势和问题

优势:算得超级快。
问题:只能满足float这种精度要求。

posted @ 2024-04-03 00:04  shandianchengzi  阅读(26)  评论(0编辑  收藏  举报  来源