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;
}