From a53549ae504b509cef0ce25dec74efc6ac544f68 Mon Sep 17 00:00:00 2001 From: Keshavram Kuduwa <131107576+kuduwa-keshavram@users.noreply.github.com> Date: Fri, 5 Jan 2024 23:05:31 +0530 Subject: [PATCH] Resolves #102 and Code Optimizations --- .../CalculateAverage_kuduwa_keshavram.java | 154 ++++++++++++------ 1 file changed, 108 insertions(+), 46 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 KEY_MAPPER = line -> { + int pivot = line.indexOf(";"); + return line.substring(0, pivot); + }; + private static final ToDoubleFunction 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 lines = Files.lines(Path.of(FILE))) { + Map 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; + + 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; + } + } + + return asDouble(value, exp, negative, decimalPlaces); } - public String toString() { - return round(min) + "/" + round(sum / count) + "/" + round(max); - } - - private double round(double value) { - return Math.round(value * 10.0) / 10.0; - } - } - - public static void main(String[] args) throws IOException { - // long before = System.currentTimeMillis(); - Map 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; } }