您当前的位置: 首页 >  Java

星拱北辰

暂无认证

  • 0浏览

    0关注

    1205博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

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

星拱北辰 发布时间:2020-02-09 12:17:55 ,浏览量:0

题目要求

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
long double result, temp;
int main() {
    while((scanf("%Lf", &temp)) != EOF) {
        result += temp * 1000000;
    }
    printf("%.5Lf", result / 1000000);
    return 0;
}
关注
打赏
1660750074
查看更多评论
立即登录/注册

微信扫码登录

0.0418s