/** * <code>toAngles</code> returns this quaternion converted to Euler rotation angles * (yaw,roll,pitch).<br> * See * http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToEuler/index.htm * * @param angles the float[] in which the angles should be stored, or null if you want a new * float[] to be created * @return the float[] in which the angles are stored. */ public float[] toAngles(float[] angles) { if (angles == null) angles = new float[3]; else if (angles.length != 3) throw new IllegalArgumentException("Angles array must have three elements"); float sqw = w * w; float sqx = x * x; float sqy = y * y; float sqz = z * z; float unit = sqx + sqy + sqz + sqw; // if normalized is one, otherwise // is correction factor float test = x * y + z * w; if (test > 0.499 * unit) { // singularity at north pole angles[1] = 2 * FastMath.atan2(x, w); angles[2] = FastMath.HALF_PI; angles[0] = 0; } else if (test < -0.499 * unit) { // singularity at south pole angles[1] = -2 * FastMath.atan2(x, w); angles[2] = -FastMath.HALF_PI; angles[0] = 0; } else { angles[1] = FastMath.atan2(2 * y * w - 2 * x * z, sqx - sqy - sqz + sqw); // roll or heading angles[2] = FastMath.asin(2 * test / unit); // pitch or attitude angles[0] = FastMath.atan2(2 * x * w - 2 * y * z, -sqx + sqy - sqz + sqw); // yaw or bank } return angles; }
public void emit() { for (int i = 1; i <= emitNum; i++) { Particle x = new Particle(loc.x, loc.y, 0, null); if (images != null) { x.setImage(images[(int) randomP(images.length)]); } else { x.setImage(null); } double temp = angle2 - angle1; double newAngle = (((rnd.nextDouble() * temp) + angle1) * Math.PI / 180); if (randomV) { x.setVel( randomP(xSpeed) * FastMath.cos(newAngle), randomP(ySpeed) * FastMath.sin(newAngle), 0); } else { x.setVel(xSpeed * FastMath.cos(newAngle), ySpeed * FastMath.sin(newAngle), 0); } x.setFade(fade); x.setFadeRate(fadeRate); x.setLoc(loc.x + random(spreadX), loc.y + random(spreadY), 0); x.setAcc(xAcc, yAcc, 0); x.setMaxAge(maxAge); x.setMaxSize(maxSize); x.setSize(size); x.setAgeRate(ageRate); x.setGrowthRate(growthRate); x.setBlink(blink); x.setColor(color); x.setMaxSpeed(new Vector3D(maxXSpeed, maxYSpeed, 0)); particleManager.addParticle(x); } }
/** * Returns {@code true} if there is no double value strictly between the arguments or the reltaive * difference between them is smaller or equal to the given tolerance. * * @param x First value. * @param y Second value. * @param eps Amount of allowed relative error. * @return {@code true} if the values are two adjacent floating point numbers or they are within * range of each other. * @since 3.1 */ public static boolean equalsWithRelativeTolerance(double x, double y, double eps) { if (equals(x, y, 1)) { return true; } final double absoluteMax = FastMath.max(FastMath.abs(x), FastMath.abs(y)); final double relativeDifference = FastMath.abs((x - y) / absoluteMax); return relativeDifference <= eps; }
public boolean intersectsBoundingBox(BoundingBox bb) { assert Vector3f.isValidVector(center) && Vector3f.isValidVector(bb.center); if (FastMath.abs(bb.center.x - center.x) < getRadius() + bb.xExtent && FastMath.abs(bb.center.y - center.y) < getRadius() + bb.yExtent && FastMath.abs(bb.center.z - center.z) < getRadius() + bb.zExtent) { return true; } return false; }
/** * <code>fromAngleNormalAxis</code> sets this quaternion to the values specified by an angle and a * normalized axis of rotation. * * @param angle the angle to rotate (in radians). * @param axis the axis of rotation (already normalized). */ public Quaternion fromAngleNormalAxis(float angle, Vector3f axis) { if (axis.x == 0 && axis.y == 0 && axis.z == 0) { loadIdentity(); } else { float halfAngle = 0.5f * angle; float sin = FastMath.sin(halfAngle); w = FastMath.cos(halfAngle); x = sin * axis.x; y = sin * axis.y; z = sin * axis.z; } return this; }
public Quaternion fromRotationMatrix( float m00, float m01, float m02, float m10, float m11, float m12, float m20, float m21, float m22) { // Use the Graphics Gems code, from // ftp://ftp.cis.upenn.edu/pub/graphics/shoemake/quatut.ps.Z // *NOT* the "Matrix and Quaternions FAQ", which has errors! // the trace is the sum of the diagonal elements; see // http://mathworld.wolfram.com/MatrixTrace.html float t = m00 + m11 + m22; // we protect the division by s by ensuring that s>=1 if (t >= 0) { // |w| >= .5 float s = FastMath.sqrt(t + 1); // |s|>=1 ... w = 0.5f * s; s = 0.5f / s; // so this division isn't bad x = (m21 - m12) * s; y = (m02 - m20) * s; z = (m10 - m01) * s; } else if ((m00 > m11) && (m00 > m22)) { float s = FastMath.sqrt(1.0f + m00 - m11 - m22); // |s|>=1 x = s * 0.5f; // |x| >= .5 s = 0.5f / s; y = (m10 + m01) * s; z = (m02 + m20) * s; w = (m21 - m12) * s; } else if (m11 > m22) { float s = FastMath.sqrt(1.0f + m11 - m00 - m22); // |s|>=1 y = s * 0.5f; // |y| >= .5 s = 0.5f / s; x = (m10 + m01) * s; z = (m21 + m12) * s; w = (m02 - m20) * s; } else { float s = FastMath.sqrt(1.0f + m22 - m00 - m11); // |s|>=1 z = s * 0.5f; // |z| >= .5 s = 0.5f / s; x = (m02 + m20) * s; y = (m21 + m12) * s; w = (m10 - m01) * s; } return this; }
/* * (non-Javadoc) * @see com.jme.bounding.BoundingVolume#intersectsWhere(com.jme.math.Ray) */ public int collideWithRay(Ray ray, CollisionResults results) { Vector3f vect1 = Vector3f.newInstance(); Vector3f diff = vect1.set(ray.getOrigin()).subtractLocal(center); float a = diff.dot(diff) - (getRadius() * getRadius()); float a1, discr, root; if (a <= 0.0) { // inside sphere a1 = ray.direction.dot(diff); discr = (a1 * a1) - a; root = FastMath.sqrt(discr); float distance = root - a1; Vector3f point = new Vector3f(ray.direction).multLocal(distance).addLocal(ray.origin); CollisionResult result = new CollisionResult(point, distance); results.addCollision(result); Vector3f.recycle(vect1); return 1; } a1 = ray.direction.dot(diff); if (a1 >= 0.0) { Vector3f.recycle(vect1); return 0; } discr = a1 * a1 - a; if (discr < 0.0) { Vector3f.recycle(vect1); return 0; } else if (discr >= FastMath.ZERO_TOLERANCE) { root = FastMath.sqrt(discr); float dist = -a1 - root; Vector3f point = new Vector3f(ray.direction).multLocal(dist).addLocal(ray.origin); results.addCollision(new CollisionResult(point, dist)); dist = -a1 + root; point = new Vector3f(ray.direction).multLocal(dist).addLocal(ray.origin); results.addCollision(new CollisionResult(point, dist)); Vector3f.recycle(vect1); return 2; } else { float dist = -a1; Vector3f point = new Vector3f(ray.direction).multLocal(dist).addLocal(ray.origin); results.addCollision(new CollisionResult(point, dist)); Vector3f.recycle(vect1); return 1; } }
@Test public void testBinomialCoefficient() { long[] bcoef5 = {1, 5, 10, 10, 5, 1}; long[] bcoef6 = {1, 6, 15, 20, 15, 6, 1}; for (int i = 0; i < 6; i++) { Assert.assertEquals("5 choose " + i, bcoef5[i], ArithmeticUtils.binomialCoefficient(5, i)); } for (int i = 0; i < 7; i++) { Assert.assertEquals("6 choose " + i, bcoef6[i], ArithmeticUtils.binomialCoefficient(6, i)); } for (int n = 1; n < 10; n++) { for (int k = 0; k <= n; k++) { Assert.assertEquals( n + " choose " + k, binomialCoefficient(n, k), ArithmeticUtils.binomialCoefficient(n, k)); Assert.assertEquals( n + " choose " + k, binomialCoefficient(n, k), ArithmeticUtils.binomialCoefficientDouble(n, k), Double.MIN_VALUE); Assert.assertEquals( n + " choose " + k, FastMath.log(binomialCoefficient(n, k)), ArithmeticUtils.binomialCoefficientLog(n, k), 10E-12); } } int[] n = {34, 66, 100, 1500, 1500}; int[] k = {17, 33, 10, 1500 - 4, 4}; for (int i = 0; i < n.length; i++) { long expected = binomialCoefficient(n[i], k[i]); Assert.assertEquals( n[i] + " choose " + k[i], expected, ArithmeticUtils.binomialCoefficient(n[i], k[i])); Assert.assertEquals( n[i] + " choose " + k[i], expected, ArithmeticUtils.binomialCoefficientDouble(n[i], k[i]), 0.0); Assert.assertEquals( "log(" + n[i] + " choose " + k[i] + ")", FastMath.log(expected), ArithmeticUtils.binomialCoefficientLog(n[i], k[i]), 0.0); } }
/** <code>normalize</code> normalizes the current <code>Quaternion</code> */ public void normalize() { float n = FastMath.invSqrt(norm()); x *= n; y *= n; z *= n; w *= n; }
/** * <code>slerp</code> sets this quaternion's value as an interpolation between two other * quaternions. * * @param q1 the first quaternion. * @param q2 the second quaternion. * @param t the amount to interpolate between the two quaternions. */ public Quaternion slerp(Quaternion q1, Quaternion q2, float t) { // Create a local quaternion to store the interpolated quaternion if (q1.x == q2.x && q1.y == q2.y && q1.z == q2.z && q1.w == q2.w) { this.set(q1); return this; } float result = (q1.x * q2.x) + (q1.y * q2.y) + (q1.z * q2.z) + (q1.w * q2.w); if (result < 0.0f) { // Negate the second quaternion and the result of the dot product q2.x = -q2.x; q2.y = -q2.y; q2.z = -q2.z; q2.w = -q2.w; result = -result; } // Set the first and second scale for the interpolation float scale0 = 1 - t; float scale1 = t; // Check if the angle between the 2 quaternions was big enough to // warrant such calculations if ((1 - result) > 0.1f) { // Get the angle between the 2 quaternions, // and then store the sin() of that angle float theta = FastMath.acos(result); float invSinTheta = 1f / FastMath.sin(theta); // Calculate the scale for q1 and q2, according to the angle and // it's sine value scale0 = FastMath.sin((1 - t) * theta) * invSinTheta; scale1 = FastMath.sin((t * theta)) * invSinTheta; } // Calculate the x, y, z and w values for the quaternion by using a // special // form of linear interpolation for quaternions. this.x = (scale0 * q1.x) + (scale1 * q2.x); this.y = (scale0 * q1.y) + (scale1 * q2.y); this.z = (scale0 * q1.z) + (scale1 * q2.z); this.w = (scale0 * q1.w) + (scale1 * q2.w); // Return the interpolated quaternion return this; }
private float getMaxAxis(Vector3f scale) { float x = FastMath.abs(scale.x); float y = FastMath.abs(scale.y); float z = FastMath.abs(scale.z); if (x >= y) { if (x >= z) { return x; } return z; } if (y >= z) { return y; } return z; }
/** * Calculates the minimum bounding sphere of 2 points. Used in welzl's algorithm. * * @param O The 1st point inside the sphere. * @param A The 2nd point inside the sphere. * @see #calcWelzl(java.nio.FloatBuffer) */ private void setSphere(Vector3f O, Vector3f A) { radius = FastMath.sqrt( ((A.x - O.x) * (A.x - O.x) + (A.y - O.y) * (A.y - O.y) + (A.z - O.z) * (A.z - O.z)) / 4f) + RADIUS_EPSILON - 1f; center.interpolate(O, A, .5f); }
/** * <code>fromAngles</code> builds a Quaternion from the Euler rotation angles (y,r,p). Note that * we are applying in order: roll, pitch, yaw but we've ordered them in x, y, and z for * convenience. See: * http://www.euclideanspace.com/maths/geometry/rotations/conversions/eulerToQuaternion/index.htm * * @param yaw the Euler yaw of rotation (in radians). (aka Bank, often rot around x) * @param roll the Euler roll of rotation (in radians). (aka Heading, often rot around y) * @param pitch the Euler pitch of rotation (in radians). (aka Attitude, often rot around z) */ public Quaternion fromAngles(float yaw, float roll, float pitch) { float angle; float sinRoll, sinPitch, sinYaw, cosRoll, cosPitch, cosYaw; angle = pitch * 0.5f; sinPitch = FastMath.sin(angle); cosPitch = FastMath.cos(angle); angle = roll * 0.5f; sinRoll = FastMath.sin(angle); cosRoll = FastMath.cos(angle); angle = yaw * 0.5f; sinYaw = FastMath.sin(angle); cosYaw = FastMath.cos(angle); // variables used to reduce multiplication calls. float cosRollXcosPitch = cosRoll * cosPitch; float sinRollXsinPitch = sinRoll * sinPitch; float cosRollXsinPitch = cosRoll * sinPitch; float sinRollXcosPitch = sinRoll * cosPitch; w = (cosRollXcosPitch * cosYaw - sinRollXsinPitch * sinYaw); x = (cosRollXcosPitch * sinYaw + sinRollXsinPitch * cosYaw); y = (sinRollXcosPitch * cosYaw + cosRollXsinPitch * sinYaw); z = (cosRollXsinPitch * cosYaw - sinRollXcosPitch * sinYaw); normalize(); return this; }
/** * <code>toAngleAxis</code> sets a given angle and axis to that represented by the current * quaternion. The values are stored as following: The axis is provided as a parameter and built * by the method, the angle is returned as a float. * * @param axisStore the object we'll store the computed axis in. * @return the angle of rotation in radians. */ public float toAngleAxis(Vector3f axisStore) { float sqrLength = x * x + y * y + z * z; float angle; if (sqrLength == 0.0f) { angle = 0.0f; if (axisStore != null) { axisStore.x = 1.0f; axisStore.y = 0.0f; axisStore.z = 0.0f; } } else { angle = (2.0f * FastMath.acos(w)); if (axisStore != null) { float invLength = (1.0f / FastMath.sqrt(sqrLength)); axisStore.x = x * invLength; axisStore.y = y * invLength; axisStore.z = z * invLength; } } return angle; }
@Test public void testFactorial() { for (int i = 1; i < 21; i++) { Assert.assertEquals(i + "! ", factorial(i), ArithmeticUtils.factorial(i)); Assert.assertEquals( i + "! ", factorial(i), ArithmeticUtils.factorialDouble(i), Double.MIN_VALUE); Assert.assertEquals( i + "! ", FastMath.log(factorial(i)), ArithmeticUtils.factorialLog(i), 10E-12); } Assert.assertEquals("0", 1, ArithmeticUtils.factorial(0)); Assert.assertEquals("0", 1.0d, ArithmeticUtils.factorialDouble(0), 1E-14); Assert.assertEquals("0", 0.0d, ArithmeticUtils.factorialLog(0), 1E-14); }
/** * Rounds the given value to the specified number of decimal places. The value is rounded using * the given method which is any method defined in {@link BigDecimal}. If {@code x} is infinite or * {@code NaN}, then the value of {@code x} is returned unchanged, regardless of the other * parameters. * * @param x Value to round. * @param scale Number of digits to the right of the decimal point. * @param roundingMethod Rounding method as defined in {@link BigDecimal}. * @return the rounded value. * @throws ArithmeticException if {@code roundingMethod == ROUND_UNNECESSARY} and the specified * scaling operation would require rounding. * @throws IllegalArgumentException if {@code roundingMethod} does not represent a valid rounding * mode. * @since 1.1 (previously in {@code MathUtils}, moved as of version 3.0) */ public static double round(double x, int scale, int roundingMethod) { try { final double rounded = (new BigDecimal(Double.toString(x)).setScale(scale, roundingMethod)).doubleValue(); // MATH-1089: negative values rounded to zero should result in negative zero return rounded == 0.0 ? rounded * FastMath.copySign(1d, x) : rounded; } catch (NumberFormatException ex) { if (Double.isInfinite(x)) { return x; } else { return Double.NaN; } } }
public BoundingVolume transform(Matrix4f trans, BoundingVolume store) { BoundingSphere sphere; if (store == null || store.getType() != BoundingVolume.Type.Sphere) { sphere = new BoundingSphere(1, new Vector3f(0, 0, 0)); } else { sphere = (BoundingSphere) store; } trans.mult(center, sphere.center); Vector3f axes = new Vector3f(1, 1, 1); trans.mult(axes, axes); float ax = getMaxAxis(axes); sphere.radius = FastMath.abs(ax * radius) + RADIUS_EPSILON - 1f; return sphere; }
/** * Returns true if both arguments are equal or within the range of allowed error (inclusive). Two * float numbers are considered equal if there are {@code (maxUlps - 1)} (or fewer) floating point * numbers between them, i.e. two adjacent floating point numbers are considered equal. Adapted * from <a href="http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm">Bruce * Dawson</a> * * @param x first value * @param y second value * @param maxUlps {@code (maxUlps - 1)} is the number of floating point values between {@code x} * and {@code y}. * @return {@code true} if there are fewer than {@code maxUlps} floating point values between * {@code x} and {@code y}. */ public static boolean equals(double x, double y, int maxUlps) { long xInt = Double.doubleToLongBits(x); long yInt = Double.doubleToLongBits(y); // Make lexicographically ordered as a two's-complement integer. if (xInt < 0) { xInt = SGN_MASK - xInt; } if (yInt < 0) { yInt = SGN_MASK - yInt; } final boolean isEqual = FastMath.abs(xInt - yInt) <= maxUlps; return isEqual && !Double.isNaN(x) && !Double.isNaN(y); }
/** * Returns true if both arguments are equal or within the range of allowed error (inclusive). Two * float numbers are considered equal if there are {@code (maxUlps - 1)} (or fewer) floating point * numbers between them, i.e. two adjacent floating point numbers are considered equal. Adapted * from <a href="http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm">Bruce * Dawson</a> * * @param x first value * @param y second value * @param maxUlps {@code (maxUlps - 1)} is the number of floating point values between {@code x} * and {@code y}. * @return {@code true} if there are fewer than {@code maxUlps} floating point values between * {@code x} and {@code y}. * @since 2.2 */ public static boolean equals(float x, float y, int maxUlps) { int xInt = Float.floatToIntBits(x); int yInt = Float.floatToIntBits(y); // Make lexicographically ordered as a two's-complement integer. if (xInt < 0) { xInt = SGN_MASK_FLOAT - xInt; } if (yInt < 0) { yInt = SGN_MASK_FLOAT - yInt; } final boolean isEqual = FastMath.abs(xInt - yInt) <= maxUlps; return isEqual && !Float.isNaN(x) && !Float.isNaN(y); }
/** * <code>getRotationColumn</code> returns one of three columns specified by the parameter. This * column is returned as a <code>Vector3f</code> object. The value is retrieved as if this * quaternion was first normalized. * * @param i the column to retrieve. Must be between 0 and 2. * @param store the vector object to store the result in. if null, a new one is created. * @return the column specified by the index. */ public Vector3f getRotationColumn(int i, Vector3f store) { if (store == null) store = new Vector3f(); float norm = norm(); if (norm != 1.0f) { norm = FastMath.invSqrt(norm); } float xx = x * x * norm; float xy = x * y * norm; float xz = x * z * norm; float xw = x * w * norm; float yy = y * y * norm; float yz = y * z * norm; float yw = y * w * norm; float zz = z * z * norm; float zw = z * w * norm; switch (i) { case 0: store.x = 1 - 2 * (yy + zz); store.y = 2 * (xy + zw); store.z = 2 * (xz - yw); break; case 1: store.x = 2 * (xy - zw); store.y = 1 - 2 * (xx + zz); store.z = 2 * (yz + xw); break; case 2: store.x = 2 * (xz + yw); store.y = 2 * (yz - xw); store.z = 1 - 2 * (xx + yy); break; default: logger.warning("Invalid column index."); throw new IllegalArgumentException("Invalid column index. " + i); } return store; }
/** * Rounds the given non-negative value to the "nearest" integer. Nearest is determined by the * rounding method specified. Rounding methods are defined in {@link BigDecimal}. * * @param unscaled Value to round. * @param sign Sign of the original, scaled value. * @param roundingMethod Rounding method, as defined in {@link BigDecimal}. * @return the rounded value. * @throws MathArithmeticException if an exact operation is required but result is not exact * @throws MathIllegalArgumentException if {@code roundingMethod} is not a valid rounding method. * @since 1.1 (previously in {@code MathUtils}, moved as of version 3.0) */ private static double roundUnscaled(double unscaled, double sign, int roundingMethod) throws MathArithmeticException, MathIllegalArgumentException { switch (roundingMethod) { case BigDecimal.ROUND_CEILING: if (sign == -1) { unscaled = FastMath.floor(FastMath.nextAfter(unscaled, Double.NEGATIVE_INFINITY)); } else { unscaled = FastMath.ceil(FastMath.nextAfter(unscaled, Double.POSITIVE_INFINITY)); } break; case BigDecimal.ROUND_DOWN: unscaled = FastMath.floor(FastMath.nextAfter(unscaled, Double.NEGATIVE_INFINITY)); break; case BigDecimal.ROUND_FLOOR: if (sign == -1) { unscaled = FastMath.ceil(FastMath.nextAfter(unscaled, Double.POSITIVE_INFINITY)); } else { unscaled = FastMath.floor(FastMath.nextAfter(unscaled, Double.NEGATIVE_INFINITY)); } break; case BigDecimal.ROUND_HALF_DOWN: { unscaled = FastMath.nextAfter(unscaled, Double.NEGATIVE_INFINITY); double fraction = unscaled - FastMath.floor(unscaled); if (fraction > 0.5) { unscaled = FastMath.ceil(unscaled); } else { unscaled = FastMath.floor(unscaled); } break; } case BigDecimal.ROUND_HALF_EVEN: { double fraction = unscaled - FastMath.floor(unscaled); if (fraction > 0.5) { unscaled = FastMath.ceil(unscaled); } else if (fraction < 0.5) { unscaled = FastMath.floor(unscaled); } else { // The following equality test is intentional and needed for rounding purposes if (FastMath.floor(unscaled) / 2.0 == FastMath.floor(Math.floor(unscaled) / 2.0)) { // even unscaled = FastMath.floor(unscaled); } else { // odd unscaled = FastMath.ceil(unscaled); } } break; } case BigDecimal.ROUND_HALF_UP: { unscaled = FastMath.nextAfter(unscaled, Double.POSITIVE_INFINITY); double fraction = unscaled - FastMath.floor(unscaled); if (fraction >= 0.5) { unscaled = FastMath.ceil(unscaled); } else { unscaled = FastMath.floor(unscaled); } break; } case BigDecimal.ROUND_UNNECESSARY: if (unscaled != FastMath.floor(unscaled)) { throw new MathArithmeticException(); } break; case BigDecimal.ROUND_UP: unscaled = FastMath.ceil(FastMath.nextAfter(unscaled, Double.POSITIVE_INFINITY)); break; default: throw new MathIllegalArgumentException( LocalizedFormats.INVALID_ROUNDING_METHOD, roundingMethod, "ROUND_CEILING", BigDecimal.ROUND_CEILING, "ROUND_DOWN", BigDecimal.ROUND_DOWN, "ROUND_FLOOR", BigDecimal.ROUND_FLOOR, "ROUND_HALF_DOWN", BigDecimal.ROUND_HALF_DOWN, "ROUND_HALF_EVEN", BigDecimal.ROUND_HALF_EVEN, "ROUND_HALF_UP", BigDecimal.ROUND_HALF_UP, "ROUND_UNNECESSARY", BigDecimal.ROUND_UNNECESSARY, "ROUND_UP", BigDecimal.ROUND_UP); } return unscaled; }
/** * Rounds the given value to the specified number of decimal places. The value is rounded using * the given method which is any method defined in {@link BigDecimal}. * * @param x Value to round. * @param scale Number of digits to the right of the decimal point. * @param roundingMethod Rounding method as defined in {@link BigDecimal}. * @return the rounded value. * @since 1.1 (previously in {@code MathUtils}, moved as of version 3.0) * @throws MathArithmeticException if an exact operation is required but result is not exact * @throws MathIllegalArgumentException if {@code roundingMethod} is not a valid rounding method. */ public static float round(float x, int scale, int roundingMethod) throws MathArithmeticException, MathIllegalArgumentException { final float sign = FastMath.copySign(1f, x); final float factor = (float) FastMath.pow(10.0f, scale) * sign; return (float) roundUnscaled(x * factor, sign, roundingMethod) / factor; }
/** * Returns true if both arguments are NaN or are equal or within the range of allowed error * (inclusive). * * @param x first value * @param y second value * @param eps the amount of absolute error to allow. * @return {@code true} if the values are equal or within range of each other, or both are NaN. * @since 2.2 */ public static boolean equalsIncludingNaN(double x, double y, double eps) { return equalsIncludingNaN(x, y) || (FastMath.abs(y - x) <= eps); }
public float distance(Vector3f point) { return FastMath.sqrt(distanceSquared(point)); }
/** * Returns {@code true} if there is no double value strictly between the arguments or the * difference between them is within the range of allowed error (inclusive). * * @param x First value. * @param y Second value. * @param eps Amount of allowed absolute error. * @return {@code true} if the values are two adjacent floating point numbers or they are within * range of each other. */ public static boolean equals(double x, double y, double eps) { return equals(x, y, 1) || FastMath.abs(y - x) <= eps; }
/** * Returns true if both arguments are NaN or are equal or within the range of allowed error * (inclusive). * * @param x first value * @param y second value * @param eps the amount of absolute error to allow. * @return {@code true} if the values are equal or within range of each other, or both are NaN. * @since 2.2 */ public static boolean equalsIncludingNaN(float x, float y, float eps) { return equalsIncludingNaN(x, y) || (FastMath.abs(y - x) <= eps); }
/** * Returns true if both arguments are equal or within the range of allowed error (inclusive). * * @param x first value * @param y second value * @param eps the amount of absolute error to allow. * @return {@code true} if the values are equal or within range of each other. * @since 2.2 */ public static boolean equals(float x, float y, float eps) { return equals(x, y, 1) || FastMath.abs(y - x) <= eps; }
/** Special version for ExtrusionLayer to match indices with vertex positions. */ public static int tessellate( float[] points, int ppos, int numPoints, int[] index, int ipos, int numRings, int vertexOffset, VertexData outTris) { int buckets = FastMath.log2(MathUtils.nextPowerOfTwo(numPoints)); buckets -= 2; // log.debug("tess use {}", buckets); TessJNI tess = new TessJNI(buckets); tess.addContour2D(index, points, ipos, numRings); // log.debug("tess ipos:{} rings:{}", ipos, numRings); if (!tess.tesselate()) return 0; int nverts = tess.getVertexCount() * 2; int nelems = tess.getElementCount() * 3; // log.debug("tess elems:{} verts:{} points:{}", nelems, nverts, numPoints); if (numPoints != nverts) { log.debug("tess ----- skip poly: " + nverts + " " + numPoints); tess.dispose(); return 0; } int sumIndices = 0; VertexData.Chunk vd = outTris.obtainChunk(); for (int offset = 0; offset < nelems; ) { int size = nelems - offset; if (VertexData.SIZE == vd.used) { vd = outTris.obtainChunk(); } if (size > VertexData.SIZE - vd.used) size = VertexData.SIZE - vd.used; tess.getElementsWithInputVertexIds(vd.vertices, vd.used, offset, size); int start = vd.used; int end = start + size; short[] indices = vd.vertices; for (int i = start; i < end; i++) { if (indices[i] < 0) { log.debug( ">>>> eeek {} {} {}", start, end, Arrays.toString(Arrays.copyOfRange(indices, start, end))); break; } indices[i] *= 2; } /* when a ring has an odd number of points one (or rather two) * additional vertices will be added. so the following rings * needs extra offset */ int shift = 0; for (int i = 0, m = numRings - 1; i < m; i++) { shift += (index[ipos + i]); /* even number of points? */ if (((index[ipos + i] >> 1) & 1) == 0) continue; for (int j = start; j < end; j++) if (indices[j] >= shift) indices[j] += 2; shift += 2; } /* shift by vertexOffset */ for (int i = start; i < end; i++) indices[i] += vertexOffset; sumIndices += size; vd.used += size; outTris.releaseChunk(); offset += size; } tess.dispose(); return sumIndices; }
/** Tests correctness for large n and sharpness of upper bound in API doc JIRA: MATH-241 */ @Test public void testBinomialCoefficientLarge() throws Exception { // This tests all legal and illegal values for n <= 200. for (int n = 0; n <= 200; n++) { for (int k = 0; k <= n; k++) { long ourResult = -1; long exactResult = -1; boolean shouldThrow = false; boolean didThrow = false; try { ourResult = ArithmeticUtils.binomialCoefficient(n, k); } catch (MathArithmeticException ex) { didThrow = true; } try { exactResult = binomialCoefficient(n, k); } catch (MathArithmeticException ex) { shouldThrow = true; } Assert.assertEquals(n + " choose " + k, exactResult, ourResult); Assert.assertEquals(n + " choose " + k, shouldThrow, didThrow); Assert.assertTrue(n + " choose " + k, (n > 66 || !didThrow)); if (!shouldThrow && exactResult > 1) { Assert.assertEquals( n + " choose " + k, 1., ArithmeticUtils.binomialCoefficientDouble(n, k) / exactResult, 1e-10); Assert.assertEquals( n + " choose " + k, 1, ArithmeticUtils.binomialCoefficientLog(n, k) / FastMath.log(exactResult), 1e-10); } } } long ourResult = ArithmeticUtils.binomialCoefficient(300, 3); long exactResult = binomialCoefficient(300, 3); Assert.assertEquals(exactResult, ourResult); ourResult = ArithmeticUtils.binomialCoefficient(700, 697); exactResult = binomialCoefficient(700, 697); Assert.assertEquals(exactResult, ourResult); // This one should throw try { ArithmeticUtils.binomialCoefficient(700, 300); Assert.fail("Expecting MathArithmeticException"); } catch (MathArithmeticException ex) { // Expected } int n = 10000; ourResult = ArithmeticUtils.binomialCoefficient(n, 3); exactResult = binomialCoefficient(n, 3); Assert.assertEquals(exactResult, ourResult); Assert.assertEquals(1, ArithmeticUtils.binomialCoefficientDouble(n, 3) / exactResult, 1e-10); Assert.assertEquals( 1, ArithmeticUtils.binomialCoefficientLog(n, 3) / FastMath.log(exactResult), 1e-10); }
/** * Evaluates the continued fraction at the value x. * * <p>The implementation of this method is based on equations 14-17 of: * * <ul> * <li>Eric W. Weisstein. "Continued Fraction." From MathWorld--A Wolfram Web Resource. <a * target="_blank" href="http://mathworld.wolfram.com/ContinuedFraction.html"> * http://mathworld.wolfram.com/ContinuedFraction.html</a> * </ul> * * The recurrence relationship defined in those equations can result in very large intermediate * results which can result in numerical overflow. As a means to combat these overflow conditions, * the intermediate results are scaled whenever they threaten to become numerically unstable. * * @param x the evaluation point. * @param epsilon maximum error allowed. * @param maxIterations maximum number of convergents * @return the value of the continued fraction evaluated at x. * @throws ConvergenceException if the algorithm fails to converge. */ public double evaluate(double x, double epsilon, int maxIterations) { double p0 = 1.0; double p1 = getA(0, x); double q0 = 0.0; double q1 = 1.0; double c = p1 / q1; int n = 0; double relativeError = Double.MAX_VALUE; while (n < maxIterations && relativeError > epsilon) { ++n; double a = getA(n, x); double b = getB(n, x); double p2 = a * p1 + b * p0; double q2 = a * q1 + b * q0; boolean infinite = false; if (Double.isInfinite(p2) || Double.isInfinite(q2)) { /* * Need to scale. Try successive powers of the larger of a or b * up to 5th power. Throw ConvergenceException if one or both * of p2, q2 still overflow. */ double scaleFactor = 1d; double lastScaleFactor = 1d; final int maxPower = 5; final double scale = FastMath.max(a, b); if (scale <= 0) { // Can't scale throw new ConvergenceException( LocalizedFormats.CONTINUED_FRACTION_INFINITY_DIVERGENCE, x); } infinite = true; for (int i = 0; i < maxPower; i++) { lastScaleFactor = scaleFactor; scaleFactor *= scale; if (a != 0.0 && a > b) { p2 = p1 / lastScaleFactor + (b / scaleFactor * p0); q2 = q1 / lastScaleFactor + (b / scaleFactor * q0); } else if (b != 0) { p2 = (a / scaleFactor * p1) + p0 / lastScaleFactor; q2 = (a / scaleFactor * q1) + q0 / lastScaleFactor; } infinite = Double.isInfinite(p2) || Double.isInfinite(q2); if (!infinite) { break; } } } if (infinite) { // Scaling failed throw new ConvergenceException(LocalizedFormats.CONTINUED_FRACTION_INFINITY_DIVERGENCE, x); } double r = p2 / q2; if (Double.isNaN(r)) { throw new ConvergenceException(LocalizedFormats.CONTINUED_FRACTION_NAN_DIVERGENCE, x); } relativeError = FastMath.abs(r / c - 1.0); // prepare for next iteration c = p2 / q2; p0 = p1; p1 = p2; q0 = q1; q1 = q2; } if (n >= maxIterations) { throw new MaxCountExceededException( LocalizedFormats.NON_CONVERGENT_CONTINUED_FRACTION, maxIterations, x); } return c; }