1 /* 2 * Copyright 2013, Google Inc. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: 8 * 9 * * Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * * Redistributions in binary form must reproduce the above 12 * copyright notice, this list of conditions and the following disclaimer 13 * in the documentation and/or other materials provided with the 14 * distribution. 15 * * Neither the name of Google Inc. nor the names of its 16 * contributors may be used to endorse or promote products derived from 17 * this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 package org.jf.util; 33 34 import java.text.DecimalFormat; 35 36 public class NumberUtils { 37 private static final int canonicalFloatNaN = Float.floatToRawIntBits(Float.NaN); 38 private static final int maxFloat = Float.floatToRawIntBits(Float.MAX_VALUE); 39 private static final int piFloat = Float.floatToRawIntBits((float)Math.PI); 40 private static final int eFloat = Float.floatToRawIntBits((float)Math.E); 41 42 private static final long canonicalDoubleNaN = Double.doubleToRawLongBits(Double.NaN); 43 private static final long maxDouble = Double.doubleToLongBits(Double.MAX_VALUE); 44 private static final long piDouble = Double.doubleToLongBits(Math.PI); 45 private static final long eDouble = Double.doubleToLongBits(Math.E); 46 47 private static final DecimalFormat format = new DecimalFormat("0.####################E0"); 48 isLikelyFloat(int value)49 public static boolean isLikelyFloat(int value) { 50 // Check for some common named float values 51 // We don't check for Float.MIN_VALUE, which has an integer representation of 1 52 if (value == canonicalFloatNaN || 53 value == maxFloat || 54 value == piFloat || 55 value == eFloat) { 56 return true; 57 } 58 59 // Check for some named integer values 60 if (value == Integer.MAX_VALUE || value == Integer.MIN_VALUE) { 61 return false; 62 } 63 64 65 // Check for likely resource id 66 int packageId = value >> 24; 67 int resourceType = value >> 16 & 0xff; 68 int resourceId = value & 0xffff; 69 if ((packageId == 0x7f || packageId == 1) && resourceType < 0x1f && resourceId < 0xfff) { 70 return false; 71 } 72 73 // a non-canocical NaN is more likely to be an integer 74 float floatValue = Float.intBitsToFloat(value); 75 if (Float.isNaN(floatValue)) { 76 return false; 77 } 78 79 // Otherwise, whichever has a shorter scientific notation representation is more likely. 80 // Integer wins the tie 81 String asInt = format.format(value); 82 String asFloat = format.format(floatValue); 83 84 // try to strip off any small imprecision near the end of the mantissa 85 int decimalPoint = asFloat.indexOf('.'); 86 int exponent = asFloat.indexOf("E"); 87 int zeros = asFloat.indexOf("000"); 88 if (zeros > decimalPoint && zeros < exponent) { 89 asFloat = asFloat.substring(0, zeros) + asFloat.substring(exponent); 90 } else { 91 int nines = asFloat.indexOf("999"); 92 if (nines > decimalPoint && nines < exponent) { 93 asFloat = asFloat.substring(0, nines) + asFloat.substring(exponent); 94 } 95 } 96 97 return asFloat.length() < asInt.length(); 98 } 99 isLikelyDouble(long value)100 public static boolean isLikelyDouble(long value) { 101 // Check for some common named double values 102 // We don't check for Double.MIN_VALUE, which has a long representation of 1 103 if (value == canonicalDoubleNaN || 104 value == maxDouble || 105 value == piDouble || 106 value == eDouble) { 107 return true; 108 } 109 110 // Check for some named long values 111 if (value == Long.MAX_VALUE || value == Long.MIN_VALUE) { 112 return false; 113 } 114 115 // a non-canocical NaN is more likely to be an long 116 double doubleValue = Double.longBitsToDouble(value); 117 if (Double.isNaN(doubleValue)) { 118 return false; 119 } 120 121 // Otherwise, whichever has a shorter scientific notation representation is more likely. 122 // Long wins the tie 123 String asLong = format.format(value); 124 String asDouble = format.format(doubleValue); 125 126 // try to strip off any small imprecision near the end of the mantissa 127 int decimalPoint = asDouble.indexOf('.'); 128 int exponent = asDouble.indexOf("E"); 129 int zeros = asDouble.indexOf("000"); 130 if (zeros > decimalPoint && zeros < exponent) { 131 asDouble = asDouble.substring(0, zeros) + asDouble.substring(exponent); 132 } else { 133 int nines = asDouble.indexOf("999"); 134 if (nines > decimalPoint && nines < exponent) { 135 asDouble = asDouble.substring(0, nines) + asDouble.substring(exponent); 136 } 137 } 138 139 return asDouble.length() < asLong.length(); 140 } 141 } 142