浮点高精求和(洛谷P2393题题解,弃坑Java拥抱C++)

题目要求

P2393题目链接

在这里插入图片描述

分析

这题实则是变态的大浮点加法,众所周知的是浮点不精确,按照IEEE754来。
原先使用Java写的,但下面分析一下为什么不能用Java写。

这代码本来是这么写的:

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        double sum = 0.0;
        String[] array = scanner.nextLine().trim().split("\\s+");
        scanner.close();
        for (String s : array) {
            sum += 1000000 * Double.parseDouble(s);
        }
        System.out.printf("%.5f", sum/1000000);
    }
}

但结果是这样的:
在这里插入图片描述

你们敢想象为什么RE?我下了数据,是空文件,连换行符都没有……
我原本以为数据错了,可能有换行符的,就加了一个特判:

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        double sum = 0.0;
        String line = scanner.nextLine();
        if ("".equals(line)) {
            System.out.println("0.00000");
            return;
        }
        String[] array = line.trim().split("\\s+");
        scanner.close();
        for (String s : array) {
            sum += 1000000 * Double.parseDouble(s);
        }
        System.out.printf("%.5f", sum/1000000);
    }
}

结果一样的,真的恶心啊。
你用nextLine()或者readLine()没用的,根本不行。
用任何Scanner都不能过,只能用BufferedReader,但也没什么头绪,毕竟BufferedReader一般来说只能读取一行或者一个字符,都不合适。
想了很久,就琢磨出一个骚方法:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Main {
    public strictfp static void main(String[] args) throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        double sum = 0.0;
        int firstRead = reader.read();
        if (firstRead == -1) {
            System.out.println("0.00000");
            return;
        }
        firstRead -= 48;
        String line = firstRead + reader.readLine();
        String[] array = line.trim().split("\\s+");
        reader.close();
        for (String s : array) {
            sum += 1000000 * Double.parseDouble(s);
        }
        System.out.printf("%.5f", sum/1000000);
    }
}

没错,先读首字符,如果没有就拜拜,打印0.00000,否则就拼接起来呗……
只过了第一个,后5个还是WA:
在这里插入图片描述

下了一个数据6,震惊,被恶心到了,double拼起来必定不精确啊,一看确实,误差挺大。

我后来加上了strictfp关键词,发现对double无效。(这个词研究不深,但测过多次,盲猜是让float按照IEEE754算,对double没啥大用……)

突然灵机一动,高精?我上BigDecimal吧,高精没毛病:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.math.RoundingMode;

public class Main {
    public strictfp static void main(String[] args) throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        BigDecimal sum = new BigDecimal(0).setScale(5, RoundingMode.HALF_EVEN);;
        int firstRead = reader.read();
        if (firstRead == -1) {
            System.out.println("0.00000");
            return;
        }
        firstRead -= 48;
        String line = firstRead + reader.readLine();
        String[] array = line.trim().split("\\s+");
        reader.close();
        for (String s : array) {
            sum = sum.add(new BigDecimal(Double.parseDouble(s)));
        }
        System.out.printf("%.5f", sum);
    }
}

结果只能说略有改观吧:
在这里插入图片描述

测试点6和8过不去的,对比发现我们的BigDecimal算的过于精确了……比给的answer精确……
我瞬间心态爆炸……
读到这里您也能想到我为了各种测试画了多少时间和精力吧,居然不是不精确就是过精确。
偏偏Java没有 long double 这回事,枯萎……

然后我弃坑Java,拾起C++,十行以内秒了这题。。。
在这里插入图片描述

一句题外话是:性能差距过大。

提示:洛谷的OJ基本面向中学信息学竞赛,所以C++是王道,你用Java人家不理你的,见好就收即可,嗯……

AC代码(C++语言描述)

#include<cstdio>
long double result, temp;
int main() {
    while((scanf("%Lf", &temp)) != EOF) {
        result += temp * 1000000;
    }
    printf("%.5Lf", result / 1000000);
    return 0;
}
发布了479 篇原创文章 · 获赞 972 · 访问量 14万+

猜你喜欢

转载自blog.csdn.net/weixin_43896318/article/details/104233352