Mercurial > dive4elements > river
diff artifacts/src/main/java/org/dive4elements/river/utils/DoubleUtil.java @ 5838:5aa05a7a34b7
Rename modules to more fitting names.
author | Sascha L. Teichmann <teichmann@intevation.de> |
---|---|
date | Thu, 25 Apr 2013 15:23:37 +0200 |
parents | flys-artifacts/src/main/java/org/dive4elements/river/utils/DoubleUtil.java@bd047b71ab37 |
children | 4897a58c8746 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/utils/DoubleUtil.java Thu Apr 25 15:23:37 2013 +0200 @@ -0,0 +1,246 @@ +package org.dive4elements.river.utils; + +import org.dive4elements.river.artifacts.math.Linear; + +import gnu.trove.TDoubleArrayList; + +import java.util.Arrays; + +import org.apache.log4j.Logger; + +/** Utils to deal with Double precision values. */ +public class DoubleUtil +{ + /** Private logger. */ + private static Logger log = Logger.getLogger(DoubleUtil.class); + + public static final double DEFAULT_STEP_PRECISION = 1e6; + + /** EPSILON for comparison of double precision values. */ + public static final double EPSILON = 1e-4; + + private DoubleUtil() { + } + + public static final double [] explode(double from, double to, double step) { + return explode(from, to, step, DEFAULT_STEP_PRECISION); + } + + public static final double round(double x, double precision) { + return Math.round(x * precision)/precision; + } + + public static final double round(double x) { + return Math.round(x * DEFAULT_STEP_PRECISION)/DEFAULT_STEP_PRECISION; + } + + /** + * Returns array with values from parameter from to to with given step width. + * from and to are included. + */ + public static final double [] explode( + double from, + double to, + double step, + double precision + ) { + double lower = from; + + double diff = to - from; + double tmp = diff / step; + int num = (int)Math.abs(Math.ceil(tmp)) + 1; + + if (num < 1) { + return new double[0]; + } + + double [] values = new double[num]; + + if (from > to) { + step = -step; + } + + double max = Math.max(from, to); + + for (int idx = 0; idx < num; idx++) { + if (lower - max > EPSILON) { + return Arrays.copyOfRange(values, 0, idx); + } + + values[idx] = round(lower, precision); + lower += step; + } + + return values; + } + + public static final double interpolateSorted( + double [] xs, + double [] ys, + double x + ) { + int lo = 0, hi = xs.length-1; + + int mid = -1; + + while (lo <= hi) { + mid = (lo + hi) >> 1; + double mx = xs[mid]; + if (x < mx) hi = mid - 1; + else if (x > mx) lo = mid + 1; + else return ys[mid]; + } + if (mid < lo) { + return lo >= xs.length + ? Double.NaN + : Linear.linear(x, xs[mid], xs[mid+1], ys[mid], ys[mid+1]); + } + return hi < 0 + ? Double.NaN + : Linear.linear(x, xs[mid-1], xs[mid], ys[mid-1], ys[mid]); + } + + public static final boolean isIncreasing(double [] array) { + int inc = 0; + int dec = 0; + int sweet = (array.length-1)/2; + for (int i = 1; i < array.length; ++i) { + if (array[i] > array[i-1]) { + if (++inc > sweet) { + return true; + } + } + else if (++dec > sweet) { + return false; + } + } + return inc > sweet; + } + + public static final double [] swap(double [] array) { + int lo = 0; + int hi = array.length-1; + while (hi > lo) { + double t = array[lo]; + array[lo] = array[hi]; + array[hi] = t; + ++lo; + --hi; + } + + return array; + } + + public static final double [] swapClone(double [] in) { + double [] out = new double[in.length]; + + for (int j = out.length-1, i = 0; j >= 0;) { + out[j--] = in[i++]; + } + + return out; + } + + public static final double [] sumDiffs(double [] in) { + double [] out = new double[in.length]; + + for (int i = 1; i < out.length; ++i) { + out[i] = out[i-1] + Math.abs(in[i-1] - in[i]); + } + + return out; + } + + public static final double [] fill(int N, double value) { + double [] result = new double[N]; + Arrays.fill(result, value); + return result; + } + + + /** Use with parseSegments. */ + public interface SegmentCallback { + void newSegment(double from, double to, double [] values); + } + + + /** Call callback for every string split by colon. + * Expected format FROM:TO:VALUE1,VALUE2,VALUE3*/ + public static final void parseSegments( + String input, + SegmentCallback callback + ) { + TDoubleArrayList vs = new TDoubleArrayList(); + + for (String segmentStr: input.split(":")) { + String [] parts = segmentStr.split(";"); + if (parts.length < 3) { + log.warn("invalid segment: '" + segmentStr + "'"); + continue; + } + try { + double from = Double.parseDouble(parts[0].trim()); + double to = Double.parseDouble(parts[1].trim()); + + vs.resetQuick(); + + for (String valueStr: parts[3].split(",")) { + vs.add(round(Double.parseDouble(valueStr.trim()))); + } + + callback.newSegment(from, to, vs.toNativeArray()); + } + catch (NumberFormatException nfe) { + log.warn("invalid segment: '" + segmentStr + "'"); + } + } + } + + public static final boolean isValid(double [][] data) { + for (double [] ds: data) { + for (double d: ds) { + if (Double.isNaN(d)) { + return false; + } + } + } + return true; + } + + + /** In an array of doubles, search and return the maximum value. */ + public static final double maxInArray(double[] values) { + double max = - Double.MAX_VALUE; + for (double d: values) { + if (d > max) max = d; + } + return max; + } + + public static void removeNaNs(TDoubleArrayList [] arrays) { + + int dest = 0; + + int A = arrays.length; + int N = arrays[0].size(); + + OUTER: for (int i = 0; i < N; ++i) { + for (int j = 0; j < A; ++j) { + TDoubleArrayList a = arrays[j]; + double v = a.getQuick(i); + if (Double.isNaN(v)) { + continue OUTER; + } + a.setQuick(dest, v); + } + ++dest; + } + + if (dest < N) { + for (int i = 0; i < A; ++i) { + arrays[i].remove(dest, N-dest); + } + } + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :