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