diff options
| author | Keshavram Kuduwa <131107576+kuduwa-keshavram@users.noreply.github.com> | 2024-01-05 23:05:31 +0530 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-01-05 18:35:31 +0100 |
| commit | a53549ae504b509cef0ce25dec74efc6ac544f68 (patch) | |
| tree | 6b4b336b94f2d027908d79d34e9e18e0e9efc4da /src/main/java/dev/morling/onebrc/CalculateAverage_kuduwa_keshavram.java | |
| parent | c4879d4104ba8f6d2c814c62726308ba7a36d845 (diff) | |
Resolves #102 and Code Optimizations
Diffstat (limited to 'src/main/java/dev/morling/onebrc/CalculateAverage_kuduwa_keshavram.java')
| -rw-r--r-- | src/main/java/dev/morling/onebrc/CalculateAverage_kuduwa_keshavram.java | 150 |
1 files changed, 106 insertions, 44 deletions
diff --git a/src/main/java/dev/morling/onebrc/CalculateAverage_kuduwa_keshavram.java b/src/main/java/dev/morling/onebrc/CalculateAverage_kuduwa_keshavram.java index 49c77c0..d9da874 100644 --- a/src/main/java/dev/morling/onebrc/CalculateAverage_kuduwa_keshavram.java +++ b/src/main/java/dev/morling/onebrc/CalculateAverage_kuduwa_keshavram.java @@ -18,62 +18,124 @@ package dev.morling.onebrc; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.util.DoubleSummaryStatistics; import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Function; +import java.util.function.ToDoubleFunction; import java.util.stream.Collectors; +import java.util.stream.Stream; public class CalculateAverage_kuduwa_keshavram { private static final String FILE = "./measurements.txt"; + private static final Function<String, String> KEY_MAPPER = line -> { + int pivot = line.indexOf(";"); + return line.substring(0, pivot); + }; + private static final ToDoubleFunction<String> VALUE_MAPPER = line -> { + int pivot = line.indexOf(";"); + return toDouble(line.substring(pivot + 1)); + }; - private record Measurement(double min, double max, double sum, long count) { - - Measurement(double initialMeasurement) { - this(initialMeasurement, initialMeasurement, initialMeasurement, 1); + public static void main(String[] args) throws IOException, InterruptedException { + try (Stream<String> lines = Files.lines(Path.of(FILE))) { + Map<String, DoubleSummaryStatistics> resultMap = lines + .parallel() + .collect( + Collectors.groupingBy(KEY_MAPPER, Collectors.summarizingDouble(VALUE_MAPPER))); + System.out.println( + resultMap.entrySet().stream() + .sorted(Map.Entry.comparingByKey()) + .map( + entry -> String.format( + "%s=%.1f/%.1f/%.1f", + entry.getKey(), + entry.getValue().getMin(), + entry.getValue().getAverage(), + entry.getValue().getMax())) + .collect(Collectors.joining(", ", "{", "}"))); + } } - public static Measurement combineWith(Measurement m1, Measurement m2) { - return new Measurement( - m1.min < m2.min ? m1.min : m2.min, - m1.max > m2.max ? m1.max : m2.max, - m1.sum + m2.sum, - m1.count + m2.count); - } + private static final long MAX_VALUE_DIVIDE_10 = Long.MAX_VALUE / 10; - public String toString() { - return round(min) + "/" + round(sum / count) + "/" + round(max); - } + private static double toDouble(String num) { + long value = 0; + int exp = 0; + boolean negative = false; + int decimalPlaces = Integer.MIN_VALUE; + for (byte ch : num.getBytes()) { + if (ch >= '0' && ch <= '9') { + value = value * 10 + (ch - '0'); + decimalPlaces++; + } + else if (ch == '-') { + negative = true; + } + else if (ch == '.') { + decimalPlaces = 0; + } + else { + break; + } + } - private double round(double value) { - return Math.round(value * 10.0) / 10.0; + return asDouble(value, exp, negative, decimalPlaces); } - } - public static void main(String[] args) throws IOException { - // long before = System.currentTimeMillis(); - Map<String, Measurement> resultMap = new ConcurrentHashMap<>(); - Files.lines(Path.of(FILE)) - .parallel() - .forEach( - line -> { - int pivot = line.indexOf(";"); - String key = line.substring(0, pivot); - Measurement measured = new Measurement(Double.parseDouble(line.substring(pivot + 1))); - Measurement existingMeasurement = resultMap.get(key); - if (existingMeasurement != null) { - resultMap.put(key, Measurement.combineWith(existingMeasurement, measured)); - } - else { - resultMap.put(key, measured); - } - }); - System.out.print("{"); - System.out.print( - resultMap.entrySet().stream() - .map(Object::toString) - .sorted() - .collect(Collectors.joining(", "))); - System.out.println("}"); - // System.out.println("Took: " + (System.currentTimeMillis() - before)); + private static double asDouble(long value, int exp, boolean negative, int decimalPlaces) { + if (decimalPlaces > 0 && value < Long.MAX_VALUE / 2) { + if (value < Long.MAX_VALUE / (1L << 32)) { + exp -= 32; + value <<= 32; + } + if (value < Long.MAX_VALUE / (1L << 16)) { + exp -= 16; + value <<= 16; + } + if (value < Long.MAX_VALUE / (1L << 8)) { + exp -= 8; + value <<= 8; + } + if (value < Long.MAX_VALUE / (1L << 4)) { + exp -= 4; + value <<= 4; + } + if (value < Long.MAX_VALUE / (1L << 2)) { + exp -= 2; + value <<= 2; + } + if (value < Long.MAX_VALUE / (1L << 1)) { + exp -= 1; + value <<= 1; + } + } + for (; decimalPlaces > 0; decimalPlaces--) { + exp--; + long mod = value % 5; + value /= 5; + int modDiv = 1; + if (value < Long.MAX_VALUE / (1L << 4)) { + exp -= 4; + value <<= 4; + modDiv <<= 4; + } + if (value < Long.MAX_VALUE / (1L << 2)) { + exp -= 2; + value <<= 2; + modDiv <<= 2; + } + if (value < Long.MAX_VALUE / (1L << 1)) { + exp -= 1; + value <<= 1; + modDiv <<= 1; + } + if (decimalPlaces > 1) + value += modDiv * mod / 5; + else + value += (modDiv * mod + 4) / 5; + } + final double d = Math.scalb((double) value, exp); + return negative ? -d : d; } } |
