--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2016 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.common.core.tests.math;
+
+import static org.eclipse.tracecompass.common.core.math.SaturatedArithmetic.add;
+import static org.eclipse.tracecompass.common.core.math.SaturatedArithmetic.multiply;
+import static org.eclipse.tracecompass.common.core.math.SaturatedArithmetic.sameSign;
+import static org.junit.Assert.*;
+
+import org.eclipse.tracecompass.common.core.math.SaturatedArithmetic;
+import org.junit.Test;
+
+/**
+ * Test suite for the {@link SaturatedArithmetic} All tests must test
+ * reciprocity as well as low and high limits
+ *
+ * @author Matthew Khouzam
+ */
+public class SaturatedArithmeticTest {
+
+ /**
+ * test absorbtion
+ */
+ @Test
+ public void testMult0() {
+ assertEquals(0, multiply(0, 0));
+ assertEquals(0, multiply(0, 1));
+ assertEquals(0, multiply(1, 0));
+ assertEquals(0, multiply(42, 0));
+ assertEquals(0, multiply(0, 42));
+ assertEquals(0, multiply(-42, 0));
+ assertEquals(0, multiply(0, -42));
+ assertEquals(0, multiply(Long.MAX_VALUE, 0));
+ assertEquals(0, multiply(0, Long.MAX_VALUE));
+ assertEquals(0, multiply(Long.MIN_VALUE, 0));
+ assertEquals(0, multiply(0, Long.MIN_VALUE));
+ }
+
+ /**
+ * test identity
+ */
+ @Test
+ public void testMult1() {
+ assertEquals(0, multiply(0, 1));
+ assertEquals(1, multiply(1, 1));
+ assertEquals(42, multiply(42, 1));
+ assertEquals(42, multiply(1, 42));
+ assertEquals(-42, multiply(-42, 1));
+ assertEquals(-42, multiply(1, -42));
+ assertEquals(Long.MAX_VALUE, multiply(Long.MAX_VALUE, 1));
+ assertEquals(Long.MAX_VALUE, multiply(1, Long.MAX_VALUE));
+ assertEquals(Long.MIN_VALUE, multiply(Long.MIN_VALUE, 1));
+ assertEquals(Long.MIN_VALUE, multiply(1, Long.MIN_VALUE));
+ }
+
+ /**
+ * test typical
+ */
+ @Test
+ public void testMult100() {
+ assertEquals(10000, multiply(100, 100));
+ assertEquals(-10000, multiply(100, -100));
+ assertEquals(-10000, multiply(-100, 100));
+ assertEquals(10000, multiply(-100, -100));
+
+ assertEquals(Long.MAX_VALUE, multiply(Long.MAX_VALUE, 100));
+ assertEquals(Long.MAX_VALUE, multiply(100, Long.MAX_VALUE));
+ assertEquals(Long.MIN_VALUE, multiply(Long.MIN_VALUE, 100));
+ assertEquals(Long.MIN_VALUE, multiply(100, Long.MIN_VALUE));
+
+ assertEquals(Long.MIN_VALUE, multiply(Long.MAX_VALUE, -100));
+ assertEquals(Long.MIN_VALUE, multiply(-100, Long.MAX_VALUE));
+ assertEquals(Long.MAX_VALUE, multiply(Long.MIN_VALUE, -100));
+ assertEquals(Long.MAX_VALUE, multiply(-100, Long.MIN_VALUE));
+ }
+
+ /**
+ * test limit
+ */
+ @Test
+ public void testMultLimit() {
+ assertEquals(Long.MAX_VALUE, multiply(Long.MAX_VALUE, Long.MAX_VALUE));
+ assertEquals(Long.MIN_VALUE, multiply(Long.MAX_VALUE, Long.MIN_VALUE));
+ assertEquals(Long.MIN_VALUE, multiply(Long.MIN_VALUE, Long.MAX_VALUE));
+ assertEquals(Long.MAX_VALUE, multiply(Long.MIN_VALUE, Long.MIN_VALUE));
+ }
+
+ /**
+ * test identity
+ */
+ @Test
+ public void testAdd0() {
+ assertEquals(0, add(0, 0));
+ assertEquals(1, add(0, 1));
+ assertEquals(1, add(1, 0));
+
+ assertEquals(42, add(42, 0));
+ assertEquals(42, add(0, 42));
+ assertEquals(-42, add(-42, 0));
+ assertEquals(-42, add(0, -42));
+
+ assertEquals(Long.MAX_VALUE, add(Long.MAX_VALUE, 0));
+ assertEquals(Long.MAX_VALUE, add(0, Long.MAX_VALUE));
+ assertEquals(Long.MIN_VALUE, add(Long.MIN_VALUE, 0));
+ assertEquals(Long.MIN_VALUE, add(0, Long.MIN_VALUE));
+ }
+
+ /**
+ * test typical
+ */
+ @Test
+ public void testAdd100() {
+ assertEquals(200, add(100, 100));
+ assertEquals(0, add(100, -100));
+ assertEquals(0, add(-100, 100));
+ assertEquals(-200, add(-100, -100));
+
+ assertEquals(Long.MAX_VALUE, add(Long.MAX_VALUE, 100));
+ assertEquals(Long.MAX_VALUE, add(100, Long.MAX_VALUE));
+ assertEquals(Long.MIN_VALUE + 100, add(Long.MIN_VALUE, 100));
+ assertEquals(Long.MIN_VALUE + 100, add(100, Long.MIN_VALUE));
+
+ assertEquals(Long.MAX_VALUE - 100, add(Long.MAX_VALUE, -100));
+ assertEquals(Long.MAX_VALUE - 100, add(-100, Long.MAX_VALUE));
+ assertEquals(Long.MIN_VALUE, add(Long.MIN_VALUE, -100));
+ assertEquals(Long.MIN_VALUE, add(-100, Long.MIN_VALUE));
+ }
+
+ /**
+ * test limit
+ */
+ @Test
+ public void testAddLimit() {
+ assertEquals(Long.MAX_VALUE, add(Long.MAX_VALUE, Long.MAX_VALUE));
+ assertEquals(-1, add(Long.MAX_VALUE, Long.MIN_VALUE)); // min value is 1
+ // larger than
+ // max value
+ assertEquals(-1, add(Long.MIN_VALUE, Long.MAX_VALUE));
+ assertEquals(Long.MIN_VALUE, add(Long.MIN_VALUE, Long.MIN_VALUE));
+ }
+
+ /**
+ * test same sign
+ */
+ @Test
+ public void testSameSign() {
+ assertTrue(sameSign(0, 0));
+ assertTrue(sameSign(0, -0));
+
+ assertFalse(sameSign(0, -100));
+ assertFalse(sameSign(-100, 0));
+ assertTrue(sameSign(0, 100));
+ assertTrue(sameSign(100, 0));
+
+ assertFalse(sameSign(-0, -100));
+ assertFalse(sameSign(-100, -0));
+ assertTrue(sameSign(-0, 100));
+ assertTrue(sameSign(100, -0));
+
+ assertTrue(sameSign(100, 100));
+ assertFalse(sameSign(100, -100));
+ assertFalse(sameSign(-100, 100));
+ assertTrue(sameSign(-100, -100));
+
+ assertTrue(sameSign(Long.MAX_VALUE, 100));
+ assertTrue(sameSign(100, Long.MAX_VALUE));
+ assertFalse(sameSign(Long.MIN_VALUE, 100));
+ assertFalse(sameSign(100, Long.MIN_VALUE));
+
+ assertFalse(sameSign(Long.MAX_VALUE, -100));
+ assertFalse(sameSign(-100, Long.MAX_VALUE));
+ assertTrue(sameSign(Long.MIN_VALUE, -100));
+ assertTrue(sameSign(-100, Long.MIN_VALUE));
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2016 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.common.core.math;
+
+/**
+ * Saturated arithmetic. These are mathematical helper functions that are used
+ * to clamp numbers to maximum and mimumum and avoid overflows.
+ *
+ * @author Matthew Khouzam
+ * @since 2.1
+ */
+public final class SaturatedArithmetic {
+
+ private SaturatedArithmetic() {
+ // do nothing
+ }
+
+ /**
+ * Saturated multiplication. It will not overflow but instead clamp the
+ * result to {@link Long#MAX_VALUE} and {@link Long#MIN_VALUE}.
+ *
+ * @param left
+ * The left long to multiply
+ * @param right
+ * The right long to multiply
+ * @return The saturated multiplication result. The mathematical, not Java
+ * version of Min(Max(MIN_VALUE, left*right), MAX_VALUE).
+ * @see <a href="http://en.wikipedia.org/wiki/Saturation_arithmetic">
+ * Saturation arithmetic</a>
+ */
+ public static long multiply(long left, long right) {
+ long retVal = left * right;
+ if ((left != 0) && ((retVal / left) != right)) {
+ return (sameSign(left, right) ? Long.MAX_VALUE : Long.MIN_VALUE);
+ }
+ return retVal;
+ }
+
+ /**
+ * Saturated addition. It will not overflow but instead clamp the result to
+ * {@link Long#MAX_VALUE} and {@link Long#MIN_VALUE}.
+ *
+ * @param left
+ * The left long to add
+ * @param right
+ * The right long to add
+ * @return The saturated addition result. The mathematical, not Java version
+ * of Min(Max(MIN_VALUE, left+right), MAX_VALUE).
+ * @see <a href="http://en.wikipedia.org/wiki/Saturation_arithmetic">
+ * Saturation arithmetic</a>
+ * @since 2.0
+ */
+ public static final long add(final long left, final long right) {
+ long retVal = left + right;
+ if (sameSign(left, right) && !sameSign(left, retVal)) {
+ if (retVal > 0 || left == Long.MIN_VALUE) {
+ return Long.MIN_VALUE;
+ }
+ return Long.MAX_VALUE;
+ }
+ return retVal;
+ }
+
+ /**
+ * Test if two numbers are the same sign or not
+ *
+ * @param left
+ * the left long
+ * @param right
+ * the right long
+ * @return true if both left and right are positive or both negative, false
+ * otherwise
+ */
+ public static boolean sameSign(final long left, final long right) {
+ return (left ^ right) >= 0;
+ }
+}
import java.nio.ByteBuffer;
import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.tracecompass.common.core.math.SaturatedArithmetic;
import org.eclipse.tracecompass.internal.tmf.core.timestamp.TmfNanoTimestamp;
import org.eclipse.tracecompass.internal.tmf.core.timestamp.TmfSecondTimestamp;
if (getScale() < scale) {
value /= scalingFactor;
} else {
- value = saturatedMult(scalingFactor, value);
+ value = SaturatedArithmetic.multiply(scalingFactor, value);
}
}
}
- value = saturatedAdd(value, offset);
+ value = SaturatedArithmetic.add(value, offset);
return create(value, scale);
}
if (ts.getValue() == Long.MIN_VALUE) {
return 1;
}
- final long delta = saturatedAdd(getValue(), -ts.getValue());
+ final long delta = SaturatedArithmetic.add(getValue(), -ts.getValue());
return Long.compare(delta, 0);
}
final ITmfTimestamp largerScale = (scale > ts.getScale()) ? this : ts;
return ts.getValue() == nts.getValue() && ts.getScale() == nts.getScale();
}
- /**
- * Saturated multiplication. It will not overflow but instead clamp the
- * result to {@link Long#MAX_VALUE} and {@link Long#MIN_VALUE}.
- *
- * @param left
- * The left long to multiply
- * @param right
- * The right long to multiply
- * @return The saturated multiplication result. The mathematical, not Java
- * version of Min(Max(MIN_VALUE, left*right), MAX_VALUE).
- * @see <a href="http://en.wikipedia.org/wiki/Saturation_arithmetic">
- * Saturation arithmetic</a>
- */
- private static long saturatedMult(long left, long right) {
- long retVal = left * right;
- if ((left != 0) && ((retVal / left) != right)) {
- return (sameSign(left, right) ? Long.MAX_VALUE : Long.MIN_VALUE);
- }
- return retVal;
- }
-
/**
* Saturated addition. It will not overflow but instead clamp the result to
* {@link Long#MAX_VALUE} and {@link Long#MIN_VALUE}.
* @see <a href="http://en.wikipedia.org/wiki/Saturation_arithmetic">
* Saturation arithmetic</a>
* @since 2.0
+ * @deprecated use {@link SaturatedArithmetic#add(long, long)} instead
*/
+ @Deprecated
protected static final long saturatedAdd(final long left, final long right) {
- long retVal = left + right;
- if (sameSign(left, right) && !sameSign(left, retVal)) {
- if (retVal > 0) {
- return Long.MIN_VALUE;
- }
- return Long.MAX_VALUE;
- }
- return retVal;
+ return SaturatedArithmetic.add(left, right);
}
- private static boolean sameSign(final long left, final long right) {
- return (left ^ right) >= 0;
- }
// ------------------------------------------------------------------------
// Object