/*
Реализация спецификаций CLDC версии 1.1 (JSR-139), MIDP версии 2.1 (JSR-118)
и других спецификаций для функционирования компактных приложений на языке
Java (мидлетов) в среде программного обеспечения Малик Эмулятор.
Copyright © 2016–2017, 2019–2023 Малик Разработчик
Это свободная программа: вы можете перераспространять ее и/или изменять
ее на условиях Меньшей Стандартной общественной лицензии GNU в том виде,
в каком она была опубликована Фондом свободного программного обеспечения;
либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.
Эта программа распространяется в надежде, что она будет полезной,
но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННЫХ ЦЕЛЕЙ. Подробнее см. в Меньшей Стандартной
общественной лицензии GNU.
Вы должны были получить копию Меньшей Стандартной общественной лицензии GNU
вместе с этой программой. Если это не так, см.
<https://www.gnu.org/licenses/>.
*/
package malik.emulator.util;
public class RealValueRepresenter extends Object
{
public static final int MIN_ORDER_DIGITS = 2;
public static final int MAX_ORDER_DIGITS = 4;
public static final int FLOAT_ORDER_DIGITS = 2;
public static final int DOUBLE_ORDER_DIGITS = 3;
public static final int MIN_SIGNIFICAND_DIGITS = 6;
public static final int MAX_SIGNIFICAND_DIGITS = 18;
public static final int FLOAT_SIGNIFICAND_DIGITS = 7;
public static final int DOUBLE_SIGNIFICAND_DIGITS = 15;
public static double pow10(double value, int power) {
if(power == Integer.MIN_VALUE) return value * 0.d;
if(power > 0)
{
return value / tab_04_00(power) / tab_08_05(power) / (power >= 0x0200 ? 0.d : 1.d);
}
if((power = -power) > 0)
{
return value * tab_04_00(power) * tab_08_05(power) * (power >= 0x0200 ? 0.d : 1.d);
}
return value;
}
private static double tab_04_00(int pow) {
switch(pow & 0x1f)
{
default:
return 0.d;
case 0:
return 1.d;
case 1:
return 1.e-001d;
case 2:
return 1.e-002d;
case 3:
return 1.e-003d;
case 4:
return 1.e-004d;
case 5:
return 1.e-005d;
case 6:
return 1.e-006d;
case 7:
return 1.e-007d;
case 8:
return 1.e-008d;
case 9:
return 1.e-009d;
case 10:
return 1.e-010d;
case 11:
return 1.e-011d;
case 12:
return 1.e-012d;
case 13:
return 1.e-013d;
case 14:
return 1.e-014d;
case 15:
return 1.e-015d;
case 16:
return 1.e-016d;
case 17:
return 1.e-017d;
case 18:
return 1.e-018d;
case 19:
return 1.e-019d;
case 20:
return 1.e-020d;
case 21:
return 1.e-021d;
case 22:
return 1.e-022d;
case 23:
return 1.e-023d;
case 24:
return 1.e-024d;
case 25:
return 1.e-025d;
case 26:
return 1.e-026d;
case 27:
return 1.e-027d;
case 28:
return 1.e-028d;
case 29:
return 1.e-029d;
case 30:
return 1.e-030d;
case 31:
return 1.e-031d;
}
}
private static double tab_08_05(int pow) {
switch((pow >> 5) & 0x0f)
{
default:
return 0.d;
case 0:
return 1.d;
case 1:
return 1.e-032d;
case 2:
return 1.e-064d;
case 3:
return 1.e-096d;
case 4:
return 1.e-128d;
case 5:
return 1.e-160d;
case 6:
return 1.e-192d;
case 7:
return 1.e-224d;
case 8:
return 1.e-256d;
case 9:
return 1.e-288d;
case 10:
return 1.e-320d;
case 11:
case 12:
case 13:
case 14:
case 15:
return 0.d;
}
}
protected final double limitValueWithFractialPart;
protected final double limitValueWithoutExponent;
protected final int orderDigits;
protected final int significandDigits;
protected final long minRepresentValue;
protected final long maxRepresentValue;
public RealValueRepresenter(int significandDigits, int orderDigits) {
long maxRepresentValue = 1L;
if(orderDigits < MIN_ORDER_DIGITS) orderDigits = MIN_ORDER_DIGITS;
if(orderDigits > MAX_ORDER_DIGITS) orderDigits = MAX_ORDER_DIGITS;
if(significandDigits < MIN_SIGNIFICAND_DIGITS) significandDigits = MIN_SIGNIFICAND_DIGITS;
if(significandDigits > MAX_SIGNIFICAND_DIGITS) significandDigits = MAX_SIGNIFICAND_DIGITS;
for(int i = significandDigits; i-- > 0; maxRepresentValue *= 10L);
this.limitValueWithFractialPart = pow10(1.d, significandDigits - 1);
this.limitValueWithoutExponent = pow10(1.d, significandDigits);
this.orderDigits = orderDigits;
this.significandDigits = significandDigits;
this.minRepresentValue = maxRepresentValue / 10L;
this.maxRepresentValue = maxRepresentValue - 1L;
}
public boolean equals(Object anot) {
RealValueRepresenter r;
return anot == this || anot instanceof RealValueRepresenter && orderDigits == (r = (RealValueRepresenter) anot).orderDigits && significandDigits == r.significandDigits;
}
public int hashCode() {
return orderDigits << 8 | significandDigits;
}
public float parseFloat(String string) throws NumberFormatException {
double result;
if("+Infinity".equals(string) || "Infinity".equals(string)) return Float.POSITIVE_INFINITY;
if("-Infinity".equals(string)) return Float.NEGATIVE_INFINITY;
if("NaN".equals(string)) return Float.NaN;
if((result = parse(string)) < (double) -Float.MAX_VALUE || result > (double) Float.MAX_VALUE)
{
throw new NumberFormatException("RealValueRepresenter.parse: недопустимый формат числа.");
}
return (float) result;
}
public double parseDouble(String string) throws NumberFormatException {
if("+Infinity".equals(string) || "Infinity".equals(string)) return Double.POSITIVE_INFINITY;
if("-Infinity".equals(string)) return Double.NEGATIVE_INFINITY;
if("NaN".equals(string)) return Double.NaN;
return parse(string);
}
public int getOrderDigits() {
return orderDigits;
}
public int getSignificandDigits() {
return significandDigits;
}
public String toString(double value) {
boolean expform;
char c;
int i;
int j;
int len;
int order;
int dotpos;
int sigdig;
long intval;
long tmp;
char[] buf;
if(value != value) return "NaN";
if(value == Double.POSITIVE_INFINITY) return "Infinity";
if(value == Double.NEGATIVE_INFINITY) return "-Infinity";
len = 0;
Array.fill(buf = new char[i = 32], 0, i, '0');
if((intval = Double.doubleToLongBits(value)) < 0L)
{
buf[len++] = '-';
value = Double.longBitsToDouble(intval &= 0x7fffffffffffffffL);
}
if(intval != 0L)
{
order = (int) (3.01029995663981195e-001d * Math.log2(value));
sigdig = significandDigits;
/* if(expform = value < 1.e-006d || value >= limitValueWithoutExponent) */
if(expform = value < 1.e-003d || value >= 1.e+007d)
{
if(order < 0) order--;
if((intval = Math.round(pow10(value, sigdig - order - 1))) < minRepresentValue)
{
intval *= 10L;
order--;
}
if(intval > maxRepresentValue)
{
intval /= 10L;
order++;
}
dotpos = len + 1;
}
else if(value < 1.e+000d)
{
intval = Math.round(pow10(value, sigdig - 1));
dotpos = len + 1;
}
else if(value < limitValueWithFractialPart)
{
if((intval = Math.round(pow10(value, sigdig - order - 1))) < minRepresentValue)
{
intval *= 10L;
order--;
}
if(intval > maxRepresentValue)
{
intval /= 10L;
order++;
}
dotpos = len + order + 1;
}
else
{
if((intval = Math.round(value)) > (tmp = maxRepresentValue)) intval = tmp;
dotpos = len + sigdig;
}
for(buf[dotpos] = '.', i = len + sigdig; i-- > len; )
{
buf[i >= dotpos ? i + 1 : i] = (char) ((int) (intval % 10L) + '0');
intval /= 10L;
}
for(len += sigdig + 2; (c = buf[len - 1]) == '0' || c == '.'; )
{
len--;
if(c == '.')
{
len += 2;
break;
}
}
if(expform)
{
buf[len++] = 'E';
if(order < 0)
{
buf[len++] = '-';
order = -order;
} else
{
buf[len++] = '+';
}
for(i = j = len + orderDigits; i-- > len; )
{
buf[i] = (char) ((order % 10) + '0');
order /= 10;
}
len = j;
}
} else
{
len += 3;
buf[len - 2] = '.';
}
return new String(buf, 0, len);
}
protected double parse(String string) throws NumberFormatException {
boolean negative;
char c;
double result;
int order;
int frac;
int len;
int i;
if(string == null || (len = string.length()) <= 0)
{
throw new NumberFormatException("RealValueRepresenter.parse: недопустимый формат числа.");
}
negative = false;
result = 0.d;
order = 0;
frac = 0;
switch(string.charAt(i = 0))
{
default:
break;
case '-':
negative = true;
/* fall through */
case '+':
case ' ':
i++;
break;
}
label0:
{
if(i < len && ((c = string.charAt(i)) >= '0' && c <= '9' || c == '.'))
{
if(c == '.') break label0;
result = (double) (c - '0');
} else
{
throw new NumberFormatException("RealValueRepresenter.parse: недопустимый формат числа.");
}
for(i++; i < len && (c = string.charAt(i)) >= '0' && c <= '9'; i++) result = (10.d * result) + (double) (c - '0');
}
if(i < len && string.charAt(i) == '.')
{
for(i++; i < len && (c = string.charAt(i)) >= '0' && c <= '9'; frac++, i++) result = (10.d * result) + (double) (c - '0');
}
if(negative)
{
result = -result;
negative = false;
}
if(i < len && ((c = string.charAt(i)) == 'E' || c == 'e'))
{
if(++i == len)
{
throw new NumberFormatException("RealValueRepresenter.parse: недопустимый формат числа.");
}
switch(string.charAt(i))
{
default:
break;
case '-':
negative = true;
/* fall through */
case '+':
i++;
break;
}
if(i == len)
{
throw new NumberFormatException("RealValueRepresenter.parse: недопустимый формат числа.");
}
for(; i < len && (c = string.charAt(i)) >= '0' && c <= '9'; i++) if((order = (10 * order) + (int) (c - '0')) > 9999)
{
throw new NumberFormatException("RealValueRepresenter.parse: недопустимый формат числа.");
}
if(negative) order = -order;
}
if(i < len || Math.abs(result = pow10(result, order - frac)) > Double.MAX_VALUE)
{
throw new NumberFormatException("RealValueRepresenter.parse: недопустимый формат числа.");
}
return result;
}
}