1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
|
package com.github.technus.tectech.util;
import java.util.Arrays;
import static java.lang.Math.abs;
import static java.lang.Math.ulp;
public class DoubleCount {
/**
* Distributes count across probabilities
*
* @param count the count to divide
* @param probabilities probability ratios to divide by, descending
* @return divided count
* @throws ArithmeticException
*/
public static double[] distribute(double count, double... probabilities) throws ArithmeticException {
if (probabilities == null || Double.isNaN(count)) {
return null;
} else if (count == 0) {
return new double[probabilities.length];
} else if (Double.isInfinite(count)) {
double[] doubles = new double[probabilities.length];
Arrays.fill(doubles, count);
return doubles;
} else {
switch (probabilities.length) {
default: {
int size = probabilities.length;
double[] output = new double[size];
size--;
double remaining = count, previous = probabilities[size], probability, out;
for (int i = size - 1; i >= 0; i--) {
probability = probabilities[i];
out = count * probability;
out -= ulpSigned(out);
remaining -= out;
output[i] = out;
if (previous < probability) {
throw new ArithmeticException("Malformed probability order: " + Arrays.toString(probabilities));
}
previous = probability;
if (probability >= 1) {
break;
}
}
if (remaining * count < 0) {//overshoot
finishIt(size, output, remaining);
} else {
output[size] = remaining;
}
return output;
}
case 1:
return new double[]{count};
case 0:
return probabilities;//empty array at hand...
}
}
}
public static double ulpSigned(double number) {
if (number == 0) {
return 0;
}
return number > 0 ? ulp(number) : -ulp(number);
}
private static void finishIt(int size, double[] output, double remaining) {
for (int i = size - 1; i >= 0; i--) {
if (abs(output[i]) >= abs(remaining)) {
output[i] -= remaining;
break;
} else {
remaining += output[i];
output[i] = 0;
}
}
}
public static double div(double count, double divisor) {
if (count == 0 || abs(divisor) == 1 || abs(count)==abs(divisor)) {
return count/divisor;
} else {
double result = count / divisor;
return result - ulpSigned(result);
}
}
public static double mul(double count, double multiplier) {
if (count == 0 || multiplier == 0 || abs(multiplier)==1 || abs(count)==1) {
return count*multiplier;
} else {
double result = count * multiplier;
return result - ulpSigned(result);
}
}
public static double sub(double count, double value) {
if (count == 0 || value == 0 || count == value) {
return count - value;
} else {
double result = count - value;
if(result==count||result==value){
return result;
}
return result - ulpSigned(result);
}
}
public static double add(double count, double value) {
if (count == 0 || value == 0 || count == -value) {
return count + value;
} else {
double result = count + value;
if(result==count||result==value){
return result;
}
return result - ulpSigned(result);
}
}
}
|