示例#1
0
  /**
   * <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;
  }
示例#2
0
  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);
    }
  }
示例#3
0
  /**
   * 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;
  }
示例#5
0
 /**
  * <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;
 }
示例#6
0
  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;
    }
  }
示例#8
0
  @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);
    }
  }
示例#9
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;
 }
示例#10
0
  /**
   * <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);
 }
示例#13
0
  /**
   * <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;
  }
示例#14
0
  /**
   * <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;
  }
示例#15
0
  @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);
  }
示例#16
0
 /**
  * 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;
  }
示例#18
0
  /**
   * 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);
  }
示例#19
0
  /**
   * 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);
  }
示例#20
0
  /**
   * <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;
  }
示例#21
0
 /**
  * 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;
 }
示例#22
0
 /**
  * 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;
 }
示例#23
0
 /**
  * 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);
 }
示例#24
0
文件: Line.java 项目: jmecn/learnJME3
 public float distance(Vector3f point) {
   return FastMath.sqrt(distanceSquared(point));
 }
示例#25
0
 /**
  * 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;
 }
示例#26
0
 /**
  * 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);
 }
示例#27
0
 /**
  * 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;
  }
示例#29
0
  /** 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;
  }