| | | @@ 変更前 1行目〜 / 変更後 1行目〜 @@ |
| 1 | 1 | | import java.util.LinkedHashMap; |
| 2 | 2 | | import java.util.Map; |
| 3 | 3 | | |
| 4 | | − | /** 露点・不快指数の計算。v1: double と Math.log / Math.pow で計算し、String.format("%.1f") で小数第1位にする素直な書き方。 */ |
| 4 | + | /** |
| 5 | + | * 露点・不快指数の計算。 |
| 6 | + | * v2: 不快指数は 10万倍した整数で正確に計算して四捨五入する(double だと 74.45 が 74.44999999999999 になり 74.4 に落ちる)。 |
| 7 | + | * 露点・絶対湿度は Math.log / Math.pow のまま(小数第1位では正確な値と一致することを60,100通りで確かめた)。 |
| 8 | + | * String.format は -0.04 を "-0.0" にするので、0 に丸まる値は "0.0" にする。湿度100%の露点は気温そのもの。 |
| 9 | + | */ |
| 5 | 10 | | public final class Dew { |
| 6 | 11 | | private Dew() {} |
| 7 | 12 | | |
| 8 | | − | static String feelOf(double di) { |
| 9 | | − | if (di < 55) return "寒い"; |
| 10 | | − | if (di < 60) return "肌寒い"; |
| 11 | | − | if (di < 65) return "何も感じない"; |
| 12 | | − | if (di < 70) return "快適"; |
| 13 | | − | if (di < 75) return "暑くない"; |
| 14 | | − | if (di < 80) return "やや暑い"; |
| 15 | | − | if (di < 85) return "暑くて汗が出る"; |
| 13 | + | /** n は不快指数 × 100000(整数) */ |
| 14 | + | static String feelOf(long n) { |
| 15 | + | if (n < 5_500_000) return "寒い"; |
| 16 | + | if (n < 6_000_000) return "肌寒い"; |
| 17 | + | if (n < 6_500_000) return "何も感じない"; |
| 18 | + | if (n < 7_000_000) return "快適"; |
| 19 | + | if (n < 7_500_000) return "暑くない"; |
| 20 | + | if (n < 8_000_000) return "やや暑い"; |
| 21 | + | if (n < 8_500_000) return "暑くて汗が出る"; |
| 16 | 22 | | return "暑くてたまらない"; |
| 23 | + | } |
| 24 | + | |
| 25 | + | /** 10万倍した整数 n を小数第1位に四捨五入した文字列(0.5 は 0 から遠い方へ) */ |
| 26 | + | static String tenthsText(long n) { |
| 27 | + | long r = (Math.abs(n) + 5000) / 10000; |
| 28 | + | return r == 0 ? "0.0" : (n < 0 ? "-" : "") + r / 10 + "." + r % 10; |
| 29 | + | } |
| 30 | + | |
| 31 | + | static String fixed1(double x) { |
| 32 | + | String s = String.format(java.util.Locale.ROOT, "%.1f", x); |
| 33 | + | return s.equals("-0.0") ? "0.0" : s; |
| 17 | 34 | | } |
| 18 | 35 | | |
| 19 | 36 | | public static Map<String, Object> calc(String temp, long humid) { |
| 20 | 37 | | Map<String, Object> out = new LinkedHashMap<>(); |
| 21 | 38 | | if (!temp.matches("-?\\d+(\\.\\d)?")) { out.put("error", "invalid_input"); return out; } |
| 22 | 39 | | double t = Double.parseDouble(temp); |
| 40 | + | long t10 = Math.round(t * 10); // 小数第1位までなので、10倍すれば整数 |
| 23 | 41 | | if (t < -20 || t > 40 || humid < 1 || humid > 100) { out.put("error", "invalid_input"); return out; } |
| 24 | 42 | | double es = 6.1078 * Math.pow(10, (7.5 * t) / (237.3 + t)); |
| 25 | 43 | | double gamma = Math.log(humid / 100.0) + (17.27 * t) / (237.7 + t); |
| 26 | | − | double dew = (237.7 * gamma) / (17.27 - gamma); |
| 27 | | − | double di = 0.81 * t + 0.01 * humid * (0.99 * t - 14.3) + 46.3; |
| 44 | + | double dew = humid == 100 ? t : (237.7 * gamma) / (17.27 - gamma); |
| 45 | + | long di = 8100 * t10 + humid * (99 * t10 - 14300) + 4_630_000; // 不快指数 × 100000(整数) |
| 28 | 46 | | double ah = (217 * es * (humid / 100.0)) / (t + 273.15); |
| 29 | | − | out.put("di", String.format("%.1f", di)); |
| 47 | + | out.put("di", tenthsText(di)); |
| 30 | 48 | | out.put("feel", feelOf(di)); |
| 31 | | − | out.put("dew", String.format("%.1f", dew)); |
| 32 | | − | out.put("abs_humidity", String.format("%.1f", ah)); |
| 49 | + | out.put("dew", fixed1(dew)); |
| 50 | + | out.put("abs_humidity", fixed1(ah)); |
| 33 | 51 | | out.put("risk", dew >= 18 ? "高い" : dew >= 12 ? "中" : "低い"); |
| 34 | 52 | | return out; |
| 35 | 53 | | } |