16d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver/*
26d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver * Copyright 2013, Google Inc.
36d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver * All rights reserved.
46d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver *
56d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver * Redistribution and use in source and binary forms, with or without
66d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver * modification, are permitted provided that the following conditions are
76d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver * met:
86d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver *
96d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver *     * Redistributions of source code must retain the above copyright
106d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver * notice, this list of conditions and the following disclaimer.
116d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver *     * Redistributions in binary form must reproduce the above
126d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver * copyright notice, this list of conditions and the following disclaimer
136d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver * in the documentation and/or other materials provided with the
146d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver * distribution.
156d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver *     * Neither the name of Google Inc. nor the names of its
166d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver * contributors may be used to endorse or promote products derived from
176d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver * this software without specific prior written permission.
186d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver *
196d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
206d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
216d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
226d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
236d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
246d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
256d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
266d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
276d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
286d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
296d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
306d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver */
316d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver
326d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruverpackage org.jf.util;
336d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver
346d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruverimport java.text.DecimalFormat;
356d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver
366d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruverpublic class NumberUtils {
376d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver    private static final int canonicalFloatNaN = Float.floatToRawIntBits(Float.NaN);
386d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver    private static final int maxFloat = Float.floatToRawIntBits(Float.MAX_VALUE);
396d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver    private static final int piFloat = Float.floatToRawIntBits((float)Math.PI);
406d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver    private static final int eFloat = Float.floatToRawIntBits((float)Math.E);
416d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver
426d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver    private static final long canonicalDoubleNaN = Double.doubleToRawLongBits(Double.NaN);
436d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver    private static final long maxDouble = Double.doubleToLongBits(Double.MAX_VALUE);
446d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver    private static final long piDouble = Double.doubleToLongBits(Math.PI);
456d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver    private static final long eDouble = Double.doubleToLongBits(Math.E);
466d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver
476d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver    private static final DecimalFormat format = new DecimalFormat("0.####################E0");
486d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver
496d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver    public static boolean isLikelyFloat(int value) {
506d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver        // Check for some common named float values
516d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver        // We don't check for Float.MIN_VALUE, which has an integer representation of 1
526d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver        if (value == canonicalFloatNaN ||
536d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver                value == maxFloat ||
546d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver                value == piFloat ||
556d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver                value == eFloat) {
566d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver            return true;
576d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver        }
586d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver
596d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver        // Check for some named integer values
606d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver        if (value == Integer.MAX_VALUE || value == Integer.MIN_VALUE) {
616d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver            return false;
626d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver        }
636d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver
646d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver
656d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver        // Check for likely resource id
666d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver        int packageId = value >> 24;
676d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver        int resourceType = value >> 16 & 0xff;
686d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver        int resourceId = value & 0xffff;
696d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver        if ((packageId == 0x7f || packageId == 1) && resourceType < 0x1f && resourceId < 0xfff) {
706d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver            return false;
716d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver        }
726d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver
736d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver        // a non-canocical NaN is more likely to be an integer
746d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver        float floatValue = Float.intBitsToFloat(value);
756d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver        if (Float.isNaN(floatValue)) {
766d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver            return false;
776d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver        }
786d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver
796d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver        // Otherwise, whichever has a shorter scientific notation representation is more likely.
806d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver        // Integer wins the tie
816d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver        String asInt = format.format(value);
826d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver        String asFloat = format.format(floatValue);
836d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver
846d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver        // try to strip off any small imprecision near the end of the mantissa
856d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver        int decimalPoint = asFloat.indexOf('.');
866d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver        int exponent = asFloat.indexOf("E");
876d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver        int zeros = asFloat.indexOf("000");
886d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver        if (zeros > decimalPoint && zeros < exponent) {
896d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver            asFloat = asFloat.substring(0, zeros) + asFloat.substring(exponent);
906d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver        } else {
916d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver            int nines = asFloat.indexOf("999");
926d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver            if (nines > decimalPoint && nines < exponent) {
936d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver                asFloat = asFloat.substring(0, nines) + asFloat.substring(exponent);
946d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver            }
956d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver        }
966d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver
976d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver        return asFloat.length() < asInt.length();
986d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver    }
996d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver
1006d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver    public static boolean isLikelyDouble(long value) {
1016d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver        // Check for some common named double values
1026d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver        // We don't check for Double.MIN_VALUE, which has a long representation of 1
1036d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver        if (value == canonicalDoubleNaN ||
1046d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver                value == maxDouble ||
1056d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver                value == piDouble ||
1066d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver                value == eDouble) {
1076d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver            return true;
1086d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver        }
1096d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver
1106d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver        // Check for some named long values
1116d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver        if (value == Long.MAX_VALUE || value == Long.MIN_VALUE) {
1126d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver            return false;
1136d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver        }
1146d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver
1156d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver        // a non-canocical NaN is more likely to be an long
1166d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver        double doubleValue = Double.longBitsToDouble(value);
1176d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver        if (Double.isNaN(doubleValue)) {
1186d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver            return false;
1196d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver        }
1206d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver
1216d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver        // Otherwise, whichever has a shorter scientific notation representation is more likely.
1226d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver        // Long wins the tie
1236d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver        String asLong = format.format(value);
1246d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver        String asDouble = format.format(doubleValue);
1256d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver
1266d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver        // try to strip off any small imprecision near the end of the mantissa
1276d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver        int decimalPoint = asDouble.indexOf('.');
1286d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver        int exponent = asDouble.indexOf("E");
1296d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver        int zeros = asDouble.indexOf("000");
1306d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver        if (zeros > decimalPoint && zeros < exponent) {
1316d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver            asDouble = asDouble.substring(0, zeros) + asDouble.substring(exponent);
1326d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver        } else {
1336d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver            int nines = asDouble.indexOf("999");
1346d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver            if (nines > decimalPoint && nines < exponent) {
1356d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver                asDouble = asDouble.substring(0, nines) + asDouble.substring(exponent);
1366d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver            }
1376d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver        }
1386d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver
1396d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver        return asDouble.length() < asLong.length();
1406d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver    }
1416d607ebe1d7bccd4fdf220f0275207cb452501bdBen Gruver}
142