AccurateMathCalc.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The ASF licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *      http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.apache.commons.math4.core.jdkmath;

  18. import java.io.PrintStream;


  19. /** Class used to compute the classical functions tables.
  20.  * @since 3.0
  21.  */
  22. final class AccurateMathCalc {

  23.     /**
  24.      * 0x40000000 - used to split a double into two parts, both with the low order bits cleared.
  25.      * Equivalent to 2^30.
  26.      */
  27.     private static final long HEX_40000000 = 0x40000000L; // 1073741824L

  28.     /** Factorial table, for Taylor series expansions. 0!, 1!, 2!, ... 19! */
  29.     private static final double[] FACT = new double[]
  30.         {
  31.         +1.0d,                        // 0
  32.         +1.0d,                        // 1
  33.         +2.0d,                        // 2
  34.         +6.0d,                        // 3
  35.         +24.0d,                       // 4
  36.         +120.0d,                      // 5
  37.         +720.0d,                      // 6
  38.         +5040.0d,                     // 7
  39.         +40320.0d,                    // 8
  40.         +362880.0d,                   // 9
  41.         +3628800.0d,                  // 10
  42.         +39916800.0d,                 // 11
  43.         +479001600.0d,                // 12
  44.         +6227020800.0d,               // 13
  45.         +87178291200.0d,              // 14
  46.         +1307674368000.0d,            // 15
  47.         +20922789888000.0d,           // 16
  48.         +355687428096000.0d,          // 17
  49.         +6402373705728000.0d,         // 18
  50.         +121645100408832000.0d,       // 19
  51.         };

  52.     /** Coefficients for slowLog. */
  53.     private static final double[][] LN_SPLIT_COEF = {
  54.         {2.0, 0.0},
  55.         {0.6666666269302368, 3.9736429850260626E-8},
  56.         {0.3999999761581421, 2.3841857910019882E-8},
  57.         {0.2857142686843872, 1.7029898543501842E-8},
  58.         {0.2222222089767456, 1.3245471311735498E-8},
  59.         {0.1818181574344635, 2.4384203044354907E-8},
  60.         {0.1538461446762085, 9.140260083262505E-9},
  61.         {0.13333332538604736, 9.220590270857665E-9},
  62.         {0.11764700710773468, 1.2393345855018391E-8},
  63.         {0.10526403784751892, 8.251545029714408E-9},
  64.         {0.0952233225107193, 1.2675934823758863E-8},
  65.         {0.08713622391223907, 1.1430250008909141E-8},
  66.         {0.07842259109020233, 2.404307984052299E-9},
  67.         {0.08371849358081818, 1.176342548272881E-8},
  68.         {0.030589580535888672, 1.2958646899018938E-9},
  69.         {0.14982303977012634, 1.225743062930824E-8},
  70.     };

  71.     /** Table start declaration. */
  72.     private static final String TABLE_START_DECL = "    {";

  73.     /** Table end declaration. */
  74.     private static final String TABLE_END_DECL   = "    };";

  75.     /**
  76.      * Private Constructor.
  77.      */
  78.     private AccurateMathCalc() {
  79.     }

  80.     /** Build the sine and cosine tables.
  81.      * @param SINE_TABLE_A table of the most significant part of the sines
  82.      * @param SINE_TABLE_B table of the least significant part of the sines
  83.      * @param COSINE_TABLE_A table of the most significant part of the cosines
  84.      * @param COSINE_TABLE_B table of the most significant part of the cosines
  85.      * @param SINE_TABLE_LEN length of the tables
  86.      * @param TANGENT_TABLE_A table of the most significant part of the tangents
  87.      * @param TANGENT_TABLE_B table of the most significant part of the tangents
  88.      */
  89.     @SuppressWarnings("unused")
  90.     private static void buildSinCosTables(double[] SINE_TABLE_A, double[] SINE_TABLE_B,
  91.                                           double[] COSINE_TABLE_A, double[] COSINE_TABLE_B,
  92.                                           int SINE_TABLE_LEN, double[] TANGENT_TABLE_A, double[] TANGENT_TABLE_B) {
  93.         final double[] result = new double[2];

  94.         /* Use taylor series for 0 <= x <= 6/8 */
  95.         for (int i = 0; i < 7; i++) {
  96.             double x = i / 8.0;

  97.             slowSin(x, result);
  98.             SINE_TABLE_A[i] = result[0];
  99.             SINE_TABLE_B[i] = result[1];

  100.             slowCos(x, result);
  101.             COSINE_TABLE_A[i] = result[0];
  102.             COSINE_TABLE_B[i] = result[1];
  103.         }

  104.         /* Use angle addition formula to complete table to 13/8, just beyond pi/2 */
  105.         for (int i = 7; i < SINE_TABLE_LEN; i++) {
  106.             double[] xs = new double[2];
  107.             double[] ys = new double[2];
  108.             double[] as = new double[2];
  109.             double[] bs = new double[2];
  110.             double[] temps = new double[2];

  111.             if ((i & 1) == 0) {
  112.                 // Even, use double angle
  113.                 xs[0] = SINE_TABLE_A[i / 2];
  114.                 xs[1] = SINE_TABLE_B[i / 2];
  115.                 ys[0] = COSINE_TABLE_A[i / 2];
  116.                 ys[1] = COSINE_TABLE_B[i / 2];

  117.                 /* compute sine */
  118.                 splitMult(xs, ys, result);
  119.                 SINE_TABLE_A[i] = result[0] * 2.0;
  120.                 SINE_TABLE_B[i] = result[1] * 2.0;

  121.                 /* Compute cosine */
  122.                 splitMult(ys, ys, as);
  123.                 splitMult(xs, xs, temps);
  124.                 temps[0] = -temps[0];
  125.                 temps[1] = -temps[1];
  126.                 splitAdd(as, temps, result);
  127.                 COSINE_TABLE_A[i] = result[0];
  128.                 COSINE_TABLE_B[i] = result[1];
  129.             } else {
  130.                 xs[0] = SINE_TABLE_A[i / 2];
  131.                 xs[1] = SINE_TABLE_B[i / 2];
  132.                 ys[0] = COSINE_TABLE_A[i / 2];
  133.                 ys[1] = COSINE_TABLE_B[i / 2];
  134.                 as[0] = SINE_TABLE_A[i / 2 + 1];
  135.                 as[1] = SINE_TABLE_B[i / 2 + 1];
  136.                 bs[0] = COSINE_TABLE_A[i / 2 + 1];
  137.                 bs[1] = COSINE_TABLE_B[i / 2 + 1];

  138.                 /* compute sine */
  139.                 splitMult(xs, bs, temps);
  140.                 splitMult(ys, as, result);
  141.                 splitAdd(result, temps, result);
  142.                 SINE_TABLE_A[i] = result[0];
  143.                 SINE_TABLE_B[i] = result[1];

  144.                 /* Compute cosine */
  145.                 splitMult(ys, bs, result);
  146.                 splitMult(xs, as, temps);
  147.                 temps[0] = -temps[0];
  148.                 temps[1] = -temps[1];
  149.                 splitAdd(result, temps, result);
  150.                 COSINE_TABLE_A[i] = result[0];
  151.                 COSINE_TABLE_B[i] = result[1];
  152.             }
  153.         }

  154.         /* Compute tangent = sine/cosine */
  155.         for (int i = 0; i < SINE_TABLE_LEN; i++) {
  156.             double[] xs = new double[2];
  157.             double[] ys = new double[2];
  158.             double[] as = new double[2];

  159.             as[0] = COSINE_TABLE_A[i];
  160.             as[1] = COSINE_TABLE_B[i];

  161.             splitReciprocal(as, ys);

  162.             xs[0] = SINE_TABLE_A[i];
  163.             xs[1] = SINE_TABLE_B[i];

  164.             splitMult(xs, ys, as);

  165.             TANGENT_TABLE_A[i] = as[0];
  166.             TANGENT_TABLE_B[i] = as[1];
  167.         }
  168.     }

  169.     /**
  170.      *  For x between 0 and pi/4 compute cosine using Talor series
  171.      *  cos(x) = 1 - x^2/2! + x^4/4! ...
  172.      * @param x number from which cosine is requested
  173.      * @param result placeholder where to put the result in extended precision
  174.      * (may be null)
  175.      * @return cos(x)
  176.      */
  177.     static double slowCos(final double x, final double[] result) {

  178.         final double[] xs = new double[2];
  179.         final double[] ys = new double[2];
  180.         final double[] facts = new double[2];
  181.         final double[] as = new double[2];
  182.         split(x, xs);
  183.         ys[0] = ys[1] = 0.0;

  184.         for (int i = FACT.length - 1; i >= 0; i--) {
  185.             splitMult(xs, ys, as);
  186.             ys[0] = as[0];
  187.             ys[1] = as[1];

  188.             if ((i & 1) != 0) { // skip odd entries
  189.                 continue;
  190.             }

  191.             split(FACT[i], as);
  192.             splitReciprocal(as, facts);

  193.             if ((i & 2) != 0) { // alternate terms are negative
  194.                 facts[0] = -facts[0];
  195.                 facts[1] = -facts[1];
  196.             }

  197.             splitAdd(ys, facts, as);
  198.             ys[0] = as[0]; ys[1] = as[1];
  199.         }

  200.         if (result != null) {
  201.             result[0] = ys[0];
  202.             result[1] = ys[1];
  203.         }

  204.         return ys[0] + ys[1];
  205.     }

  206.     /**
  207.      * For x between 0 and pi/4 compute sine using Taylor expansion:
  208.      * sin(x) = x - x^3/3! + x^5/5! - x^7/7! ...
  209.      * @param x number from which sine is requested
  210.      * @param result placeholder where to put the result in extended precision
  211.      * (may be null)
  212.      * @return sin(x)
  213.      */
  214.     static double slowSin(final double x, final double[] result) {
  215.         final double[] xs = new double[2];
  216.         final double[] ys = new double[2];
  217.         final double[] facts = new double[2];
  218.         final double[] as = new double[2];
  219.         split(x, xs);
  220.         ys[0] = ys[1] = 0.0;

  221.         for (int i = FACT.length - 1; i >= 0; i--) {
  222.             splitMult(xs, ys, as);
  223.             ys[0] = as[0];
  224.             ys[1] = as[1];

  225.             if ((i & 1) == 0) { // Ignore even numbers
  226.                 continue;
  227.             }

  228.             split(FACT[i], as);
  229.             splitReciprocal(as, facts);

  230.             if ((i & 2) != 0) { // alternate terms are negative
  231.                 facts[0] = -facts[0];
  232.                 facts[1] = -facts[1];
  233.             }

  234.             splitAdd(ys, facts, as);
  235.             ys[0] = as[0]; ys[1] = as[1];
  236.         }

  237.         if (result != null) {
  238.             result[0] = ys[0];
  239.             result[1] = ys[1];
  240.         }

  241.         return ys[0] + ys[1];
  242.     }


  243.     /**
  244.      *  For x between 0 and 1, returns exp(x), uses extended precision.
  245.      *  @param x argument of exponential
  246.      *  @param result placeholder where to place exp(x) split in two terms
  247.      *  for extra precision (i.e. exp(x) = result[0] + result[1]
  248.      *  @return exp(x)
  249.      */
  250.     static double slowexp(final double x, final double[] result) {
  251.         final double[] xs = new double[2];
  252.         final double[] ys = new double[2];
  253.         final double[] facts = new double[2];
  254.         final double[] as = new double[2];
  255.         split(x, xs);
  256.         ys[0] = ys[1] = 0.0;

  257.         for (int i = FACT.length - 1; i >= 0; i--) {
  258.             splitMult(xs, ys, as);
  259.             ys[0] = as[0];
  260.             ys[1] = as[1];

  261.             split(FACT[i], as);
  262.             splitReciprocal(as, facts);

  263.             splitAdd(ys, facts, as);
  264.             ys[0] = as[0];
  265.             ys[1] = as[1];
  266.         }

  267.         if (result != null) {
  268.             result[0] = ys[0];
  269.             result[1] = ys[1];
  270.         }

  271.         return ys[0] + ys[1];
  272.     }

  273.     /** Compute split[0], split[1] such that their sum is equal to d,
  274.      * and split[0] has its 30 least significant bits as zero.
  275.      * @param d number to split
  276.      * @param split placeholder where to place the result
  277.      */
  278.     private static void split(final double d, final double[] split) {
  279.         if (d < 8e298 && d > -8e298) {
  280.             final double a = d * HEX_40000000;
  281.             split[0] = (d + a) - a;
  282.             split[1] = d - split[0];
  283.         } else {
  284.             final double a = d * 9.31322574615478515625E-10;
  285.             split[0] = (d + a - d) * HEX_40000000;
  286.             split[1] = d - split[0];
  287.         }
  288.     }

  289.     /** Recompute a split.
  290.      * @param a input/out array containing the split, changed
  291.      * on output
  292.      */
  293.     private static void resplit(final double[] a) {
  294.         final double c = a[0] + a[1];
  295.         final double d = -(c - a[0] - a[1]);

  296.         if (c < 8e298 && c > -8e298) { // MAGIC NUMBER
  297.             double z = c * HEX_40000000;
  298.             a[0] = (c + z) - z;
  299.             a[1] = c - a[0] + d;
  300.         } else {
  301.             double z = c * 9.31322574615478515625E-10;
  302.             a[0] = (c + z - c) * HEX_40000000;
  303.             a[1] = c - a[0] + d;
  304.         }
  305.     }

  306.     /** Multiply two numbers in split form.
  307.      * @param a first term of multiplication
  308.      * @param b second term of multiplication
  309.      * @param ans placeholder where to put the result
  310.      */
  311.     private static void splitMult(double[] a, double[] b, double[] ans) {
  312.         ans[0] = a[0] * b[0];
  313.         ans[1] = a[0] * b[1] + a[1] * b[0] + a[1] * b[1];

  314.         /* Resplit */
  315.         resplit(ans);
  316.     }

  317.     /** Add two numbers in split form.
  318.      * @param a first term of addition
  319.      * @param b second term of addition
  320.      * @param ans placeholder where to put the result
  321.      */
  322.     private static void splitAdd(final double[] a, final double[] b, final double[] ans) {
  323.         ans[0] = a[0] + b[0];
  324.         ans[1] = a[1] + b[1];

  325.         resplit(ans);
  326.     }

  327.     /** Compute the reciprocal of in.  Use the following algorithm.
  328.      *  in = c + d.
  329.      *  want to find x + y such that x+y = 1/(c+d) and x is much
  330.      *  larger than y and x has several zero bits on the right.
  331.      *
  332.      *  Set b = 1/(2^22),  a = 1 - b.  Thus (a+b) = 1.
  333.      *  Use following identity to compute (a+b)/(c+d)
  334.      *
  335.      *  (a+b)/(c+d)  =   a/c   +    (bc - ad) / (c^2 + cd)
  336.      *  set x = a/c  and y = (bc - ad) / (c^2 + cd)
  337.      *  This will be close to the right answer, but there will be
  338.      *  some rounding in the calculation of X.  So by carefully
  339.      *  computing 1 - (c+d)(x+y) we can compute an error and
  340.      *  add that back in.   This is done carefully so that terms
  341.      *  of similar size are subtracted first.
  342.      *  @param in initial number, in split form
  343.      *  @param result placeholder where to put the result
  344.      */
  345.     static void splitReciprocal(final double[] in, final double[] result) {
  346.         final double b = 1.0 / 4194304.0;
  347.         final double a = 1.0 - b;

  348.         if (in[0] == 0.0) {
  349.             in[0] = in[1];
  350.             in[1] = 0.0;
  351.         }

  352.         result[0] = a / in[0];
  353.         result[1] = (b * in[0] - a * in[1]) / (in[0] * in[0] + in[0] * in[1]);

  354.         if (result[1] != result[1]) { // can happen if result[1] is NAN
  355.             result[1] = 0.0;
  356.         }

  357.         /* Resplit */
  358.         resplit(result);

  359.         for (int i = 0; i < 2; i++) {
  360.             /* this may be overkill, probably once is enough */
  361.             double err = 1.0 - result[0] * in[0] - result[0] * in[1] -
  362.                 result[1] * in[0] - result[1] * in[1];
  363.             /*err = 1.0 - err; */
  364.             err *= result[0] + result[1];
  365.             /*printf("err = %16e\n", err); */
  366.             result[1] += err;
  367.         }
  368.     }

  369.     /** Compute (a[0] + a[1]) * (b[0] + b[1]) in extended precision.
  370.      * @param a first term of the multiplication
  371.      * @param b second term of the multiplication
  372.      * @param result placeholder where to put the result
  373.      */
  374.     private static void quadMult(final double[] a, final double[] b, final double[] result) {
  375.         final double[] xs = new double[2];
  376.         final double[] ys = new double[2];
  377.         final double[] zs = new double[2];

  378.         /* a[0] * b[0] */
  379.         split(a[0], xs);
  380.         split(b[0], ys);
  381.         splitMult(xs, ys, zs);

  382.         result[0] = zs[0];
  383.         result[1] = zs[1];

  384.         /* a[0] * b[1] */
  385.         split(b[1], ys);
  386.         splitMult(xs, ys, zs);

  387.         double tmp = result[0] + zs[0];
  388.         result[1] -= tmp - result[0] - zs[0];
  389.         result[0] = tmp;
  390.         tmp = result[0] + zs[1];
  391.         result[1] -= tmp - result[0] - zs[1];
  392.         result[0] = tmp;

  393.         /* a[1] * b[0] */
  394.         split(a[1], xs);
  395.         split(b[0], ys);
  396.         splitMult(xs, ys, zs);

  397.         tmp = result[0] + zs[0];
  398.         result[1] -= tmp - result[0] - zs[0];
  399.         result[0] = tmp;
  400.         tmp = result[0] + zs[1];
  401.         result[1] -= tmp - result[0] - zs[1];
  402.         result[0] = tmp;

  403.         /* a[1] * b[0] */
  404.         split(a[1], xs);
  405.         split(b[1], ys);
  406.         splitMult(xs, ys, zs);

  407.         tmp = result[0] + zs[0];
  408.         result[1] -= tmp - result[0] - zs[0];
  409.         result[0] = tmp;
  410.         tmp = result[0] + zs[1];
  411.         result[1] -= tmp - result[0] - zs[1];
  412.         result[0] = tmp;
  413.     }

  414.     /** Compute exp(p) for a integer p in extended precision.
  415.      * @param p integer whose exponential is requested
  416.      * @param result placeholder where to put the result in extended precision
  417.      * @return exp(p) in standard precision (equal to result[0] + result[1])
  418.      */
  419.     static double expint(int p, final double[] result) {
  420.         //double x = M_E;
  421.         final double[] xs = new double[2];
  422.         final double[] as = new double[2];
  423.         final double[] ys = new double[2];
  424.         //split(x, xs);
  425.         //xs[1] = (double)(2.7182818284590452353602874713526625L - xs[0]);
  426.         //xs[0] = 2.71827697753906250000;
  427.         //xs[1] = 4.85091998273542816811e-06;
  428.         //xs[0] = Double.longBitsToDouble(0x4005bf0800000000L);
  429.         //xs[1] = Double.longBitsToDouble(0x3ed458a2bb4a9b00L);

  430.         /* E */
  431.         xs[0] = 2.718281828459045;
  432.         xs[1] = 1.4456468917292502E-16;

  433.         split(1.0, ys);

  434.         while (p > 0) {
  435.             if ((p & 1) != 0) {
  436.                 quadMult(ys, xs, as);
  437.                 ys[0] = as[0]; ys[1] = as[1];
  438.             }

  439.             quadMult(xs, xs, as);
  440.             xs[0] = as[0]; xs[1] = as[1];

  441.             p >>= 1;
  442.         }

  443.         if (result != null) {
  444.             result[0] = ys[0];
  445.             result[1] = ys[1];

  446.             resplit(result);
  447.         }

  448.         return ys[0] + ys[1];
  449.     }
  450.     /** xi in the range of [1, 2].
  451.      *                                3        5        7
  452.      *      x+1           /          x        x        x          \
  453.      *  ln ----- =   2 *  |  x  +   ----  +  ----  +  ---- + ...  |
  454.      *      1-x           \          3        5        7          /
  455.      *
  456.      * So, compute a Remez approximation of the following function
  457.      *
  458.      *  ln ((sqrt(x)+1)/(1-sqrt(x)))  /  x
  459.      *
  460.      * This will be an even function with only positive coefficents.
  461.      * x is in the range [0 - 1/3].
  462.      *
  463.      * Transform xi for input to the above function by setting
  464.      * x = (xi-1)/(xi+1).   Input to the polynomial is x^2, then
  465.      * the result is multiplied by x.
  466.      * @param xi number from which log is requested
  467.      * @return log(xi)
  468.      */
  469.     static double[] slowLog(double xi) {
  470.         double[] x = new double[2];
  471.         double[] x2 = new double[2];
  472.         double[] y = new double[2];
  473.         double[] a = new double[2];

  474.         split(xi, x);

  475.         /* Set X = (x-1)/(x+1) */
  476.         x[0] += 1.0;
  477.         resplit(x);
  478.         splitReciprocal(x, a);
  479.         x[0] -= 2.0;
  480.         resplit(x);
  481.         splitMult(x, a, y);
  482.         x[0] = y[0];
  483.         x[1] = y[1];

  484.         /* Square X -> X2*/
  485.         splitMult(x, x, x2);


  486.         //x[0] -= 1.0;
  487.         //resplit(x);

  488.         y[0] = LN_SPLIT_COEF[LN_SPLIT_COEF.length - 1][0];
  489.         y[1] = LN_SPLIT_COEF[LN_SPLIT_COEF.length - 1][1];

  490.         for (int i = LN_SPLIT_COEF.length - 2; i >= 0; i--) {
  491.             splitMult(y, x2, a);
  492.             y[0] = a[0];
  493.             y[1] = a[1];
  494.             splitAdd(y, LN_SPLIT_COEF[i], a);
  495.             y[0] = a[0];
  496.             y[1] = a[1];
  497.         }

  498.         splitMult(y, x, a);
  499.         y[0] = a[0];
  500.         y[1] = a[1];

  501.         return y;
  502.     }


  503.     /**
  504.      * Print an array.
  505.      * @param out text output stream where output should be printed
  506.      * @param name array name
  507.      * @param expectedLen expected length of the array
  508.      * @param array2d array data
  509.      */
  510.     static void printarray(PrintStream out, String name, int expectedLen, double[][] array2d) {
  511.         out.println(name);
  512.         checkLen(expectedLen, array2d.length);
  513.         out.println(TABLE_START_DECL + " ");
  514.         int i = 0;
  515.         for (double[] array : array2d) { // "double array[]" causes PMD parsing error
  516.             out.print("        {");
  517.             for (double d : array) { // assume inner array has very few entries
  518.                 out.printf("%-25.25s", format(d)); // multiple entries per line
  519.             }
  520.             out.println("}, // " + i++);
  521.         }
  522.         out.println(TABLE_END_DECL);
  523.     }

  524.     /**
  525.      * Print an array.
  526.      * @param out text output stream where output should be printed
  527.      * @param name array name
  528.      * @param expectedLen expected length of the array
  529.      * @param array array data
  530.      */
  531.     static void printarray(PrintStream out, String name, int expectedLen, double[] array) {
  532.         out.println(name + "=");
  533.         checkLen(expectedLen, array.length);
  534.         out.println(TABLE_START_DECL);
  535.         for (double d : array) {
  536.             out.printf("        %s%n", format(d)); // one entry per line
  537.         }
  538.         out.println(TABLE_END_DECL);
  539.     }

  540.     /** Format a double.
  541.      * @param d double number to format
  542.      * @return formatted number
  543.      */
  544.     static String format(double d) {
  545.         if (Double.isNaN(d)) {
  546.             return "Double.NaN,";
  547.         } else {
  548.             return ((d >= 0) ? "+" : "") + Double.toString(d) + "d,";
  549.         }
  550.     }

  551.     /**
  552.      * Check two lengths are equal.
  553.      * @param expectedLen expected length
  554.      * @param actual actual length
  555.      * @throws IllegalStateException if the two lengths are not equal
  556.      */
  557.     private static void checkLen(int expectedLen, int actual) {
  558.         if (expectedLen != actual) {
  559.             throw new IllegalStateException(actual + " != " + expectedLen);
  560.         }
  561.     }
  562. }