• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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