/*
Реализация среды исполнения языка программирования
Объектно-ориентированный продвинутый векторный транслятор
Copyright © 2021, 2024 Малик Разработчик
Это свободная программа: вы можете перераспространять ее и/или изменять
ее на условиях Меньшей Стандартной общественной лицензии GNU в том виде,
в каком она была опубликована Фондом свободного программного обеспечения;
либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.
Эта программа распространяется в надежде, что она будет полезной,
но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННЫХ ЦЕЛЕЙ. Подробнее см. в Меньшей Стандартной
общественной лицензии GNU.
Вы должны были получить копию Меньшей Стандартной общественной лицензии GNU
вместе с этой программой. Если это не так, см.
<https://www.gnu.org/licenses/>.
*/
package avt.lang.math;
import avt.lang.array.*;
public class RealRepresenter(Object, Math)
{
public static final int MIN_ORDER_DIGITS = 1;
public static final int MAX_ORDER_DIGITS = 4;
public static final int REAL_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 = 2;
public static final int MAX_SIGNIFICAND_DIGITS = 20;
public static final int REAL_SIGNIFICAND_DIGITS = 20;
public static final int FLOAT_SIGNIFICAND_DIGITS = 8;
public static final int DOUBLE_SIGNIFICAND_DIGITS = 17;
private static final long2 MUL_MIN = new long2 { 0xccccccccccccccccL, 0x0cccccccccccccccL };
public static real pow10(real value, int power) {
if(power > 0)
{
for(; power >= 0x1000; power -= 0x1000) value *= 1e+4096;
return value * tab_04_00(power) * tab_08_05(power) * tab_11_09(power);
}
if(power < 0)
{
for(power = -power; power >= 0x1000; power -= 0x1000) value /= 1e+4096;
return value / tab_04_00(power) / tab_08_05(power) / tab_11_09(power);
}
return value;
}
protected static boolean equals(CharArray string0, String string1) {
return string0 instanceof String ? string1.equals(string0) : string1.length == string0.length && string1.contentEquals(string0);
}
protected static long2 round(real value) {
if(Real.isNaN(value)) return 0;
if(value <= -0x1.0p+127) return Int128.MIN_VALUE;
if(value >= +0x1.0p+127) return Int128.MAX_VALUE;
long2 bits = Real.toLong2Bits(value);
long2 result = Long2.setElement(bits, 1, 0);
int exp = (int) bits[1];
boolean negative = exp < 0;
if((exp &= 0x7fff) >= 0x403e)
{
result = Int128.shiftLeft(result, exp - 0x403e);
} else
{
long sig = (long) result;
result = (sig >>> (0x403e - exp)) + ((sig >>> (0x403d - exp)) & 1);
}
return !negative ? result : Int128.neg(result);
}
private static real tab_04_00(int power) {
switch(power & 0x1f)
{
case 0: return 1e+0000;
case 1: return 1e+0001;
case 2: return 1e+0002;
case 3: return 1e+0003;
case 4: return 1e+0004;
case 5: return 1e+0005;
case 6: return 1e+0006;
case 7: return 1e+0007;
case 8: return 1e+0008;
case 9: return 1e+0009;
case 10: return 1e+0010;
case 11: return 1e+0011;
case 12: return 1e+0012;
case 13: return 1e+0013;
case 14: return 1e+0014;
case 15: return 1e+0015;
case 16: return 1e+0016;
case 17: return 1e+0017;
case 18: return 1e+0018;
case 19: return 1e+0019;
case 20: return 1e+0020;
case 21: return 1e+0021;
case 22: return 1e+0022;
case 23: return 1e+0023;
case 24: return 1e+0024;
case 25: return 1e+0025;
case 26: return 1e+0026;
case 27: return 1e+0027;
case 28: return 1e+0028;
case 29: return 1e+0029;
case 30: return 1e+0030;
default: return 1e+0031;
}
}
private static real tab_08_05(int power) {
switch(power >> 5 & 0x0f)
{
case 0: return 1e+0000;
case 1: return 1e+0032;
case 2: return 1e+0064;
case 3: return 1e+0096;
case 4: return 1e+0128;
case 5: return 1e+0160;
case 6: return 1e+0192;
case 7: return 1e+0224;
case 8: return 1e+0256;
case 9: return 1e+0288;
case 10: return 1e+0320;
case 11: return 1e+0352;
case 12: return 1e+0384;
case 13: return 1e+0416;
case 14: return 1e+0448;
default: return 1e+0480;
}
}
private static real tab_11_09(int power) {
switch(power >> 9 & 0x07)
{
case 0: return 1e+0000;
case 1: return 1e+0512;
case 2: return 1e+1024;
case 3: return 1e+1536;
case 4: return 1e+2048;
case 5: return 1e+2560;
case 6: return 1e+3072;
default: return 1e+3584;
}
}
protected final boolean fldSigAll; /* обязательное требование вывода всех значащих цифр: fldSigAll ? "5.0000000" : "5.0" */
protected final boolean fldOrdAll; /* обязательное требование вывода всех цифр порядка: fldOrdAll ? "5.0E+0010" : "5.0E+10" */
protected final boolean fldSigSign; /* обязательное требование вывода знака перед мантиссой: fldSigSign ? "+5.0" : "5.0" */
protected final boolean fldOrdSign; /* обязательное требование вывода знака перед порядком: fldOrdSign ? "5.0E+10" : "5.0E10" */
protected final boolean fldExpForm; /* обязательное требование вывода порядка: fldExpForm ? "5.0E+0" : "5.0" */
protected final int fldSigDigits; /* максимальное количество выводимых цифр мантиссы */
protected final int fldOrdDigits; /* минимальное количество выводимых цифр порядка */
protected final long2 fldMinRepresentValue; /* 10^(fldSigDigits-1) как int128 */
protected final long2 fldMaxRepresentValue; /* (10^fldSigDigits)-1 как int128 */
protected final real fldLimitValueWithFractialPart; /* 10^(fldSigDigits-1) */
protected final real fldLimitValueWithoutExponent; /* 10^fldSigDigits */
public (int sigDigits, int ordDigits): this(sigDigits, ordDigits, false, true, false, false, true) { }
public (int sigDigits, int ordDigits, boolean sigAll, boolean ordAll): this(sigDigits, ordDigits, sigAll, ordAll, false, false, true) { }
public (int sigDigits, int ordDigits, boolean sigAll, boolean ordAll, boolean expForm): this(sigDigits, ordDigits, sigAll, ordAll, expForm, false, true) { }
public (int sigDigits, int ordDigits, boolean sigAll, boolean ordAll, boolean expForm, boolean sigSign, boolean ordSign) {
if(sigDigits < MIN_SIGNIFICAND_DIGITS) sigDigits = MIN_SIGNIFICAND_DIGITS;
if(sigDigits > MAX_SIGNIFICAND_DIGITS) sigDigits = MAX_SIGNIFICAND_DIGITS;
if(ordDigits < MIN_ORDER_DIGITS) ordDigits = MIN_ORDER_DIGITS;
if(ordDigits > MAX_ORDER_DIGITS) ordDigits = MAX_ORDER_DIGITS;
long2 maxValue = 1;
for(int index = sigDigits - 1; index-- > 0; ) maxValue = Int128.mul(maxValue, 10);
fldSigAll = sigAll;
fldOrdAll = ordAll;
fldSigSign = sigSign;
fldOrdSign = ordSign;
fldExpForm = expForm;
fldSigDigits = sigDigits;
fldOrdDigits = ordDigits;
fldMinRepresentValue = maxValue;
fldMaxRepresentValue = Int128.sub(Int128.mul(maxValue, 10), 1);
fldLimitValueWithFractialPart = pow10(1, sigDigits - 1);
fldLimitValueWithoutExponent = pow10(1, sigDigits);
}
public boolean equals(Object anot) {
if(anot == this) return true;
if(!(anot instanceof RealRepresenter)) return false;
RealRepresenter repr = (RealRepresenter) anot;
return
fldSigAll == repr.fldSigAll &&
fldOrdAll == repr.fldOrdAll &&
fldSigSign == repr.fldSigSign &&
fldOrdSign == repr.fldOrdSign &&
fldExpForm == repr.fldExpForm &&
fldSigDigits == repr.fldSigDigits &&
fldOrdDigits == repr.fldOrdDigits
;
}
public int hashCode() {
return
(fldSigAll ? 0b00001 : 0) |
(fldOrdAll ? 0b00010 : 0) |
(fldSigSign ? 0b00100 : 0) |
(fldOrdSign ? 0b01000 : 0) |
(fldExpForm ? 0b10000 : 0) |
(fldSigDigits - MIN_SIGNIFICAND_DIGITS << 8) |
(fldOrdDigits - MIN_ORDER_DIGITS << 16)
;
}
public long hashCodeAsLong() {
return
(fldSigAll ? 0b00001 : 0) |
(fldOrdAll ? 0b00010 : 0) |
(fldSigSign ? 0b00100 : 0) |
(fldOrdSign ? 0b01000 : 0) |
(fldExpForm ? 0b10000 : 0) |
(fldSigDigits - MIN_SIGNIFICAND_DIGITS << 8) |
(fldOrdDigits - MIN_ORDER_DIGITS << 16)
;
}
public int writeTo(MutableCharArray dst, int offset, real value) {
if(dst == null)
{
throw new NullPointerException(String.format(avt.lang.package.getResourceString("null-pointer.argument"), new Object[] { "dst" }));
}
char[] result = toCharArray(value);
int length = result.length;
if(dst instanceof char[])
{
Array.copy(result, 0, (char[]) dst, offset, length);
}
else for(int index = 0; index < length; offset++, index++)
{
dst[offset] = result[index];
}
return offset + length;
}
public float parseFloat(CharArray string) {
if(string == null)
{
throw new NullPointerException(String.format(avt.lang.package.getResourceString("null-pointer.argument"), new Object[] { "string" }));
}
if(equals(string, "+Infinity") || equals(string, "Infinity")) return Float.POSITIVE_INFINITY;
if(equals(string, "-Infinity")) return Float.NEGATIVE_INFINITY;
if(equals(string, "NaN")) return Float.NAN;
real result = parse(string);
if(result < -Float.MAX_VALUE || result > Float.MAX_VALUE)
{
throw new NumberFormatException(avt.lang.package.getResourceString("illegal-argument.number-format"));
}
return (float) result;
}
public double parseDouble(CharArray string) {
if(string == null)
{
throw new NullPointerException(String.format(avt.lang.package.getResourceString("null-pointer.argument"), new Object[] { "string" }));
}
if(equals(string, "+Infinity") || equals(string, "Infinity")) return Double.POSITIVE_INFINITY;
if(equals(string, "-Infinity")) return Double.NEGATIVE_INFINITY;
if(equals(string, "NaN")) return Double.NAN;
real result = parse(string);
if(result < -Double.MAX_VALUE || result > Double.MAX_VALUE)
{
throw new NumberFormatException(avt.lang.package.getResourceString("illegal-argument.number-format"));
}
return (double) result;
}
public real parseReal(CharArray string) {
if(string == null)
{
throw new NullPointerException(String.format(avt.lang.package.getResourceString("null-pointer.argument"), new Object[] { "string" }));
}
if(equals(string, "+Infinity") || equals(string, "Infinity")) return Real.POSITIVE_INFINITY;
if(equals(string, "-Infinity")) return Real.NEGATIVE_INFINITY;
if(equals(string, "NaN")) return Real.NAN;
real result = parse(string);
if(result < -Real.MAX_VALUE || result > Real.MAX_VALUE)
{
throw new NumberFormatException(avt.lang.package.getResourceString("illegal-argument.number-format"));
}
return result;
}
public char[] toCharArray(real value) {
return
Real.isNaN(value) ? "NaN".toCharArray() :
value == Real.POSITIVE_INFINITY ? "Infinity".toCharArray() :
value == Real.NEGATIVE_INFINITY ? "-Infinity".toCharArray() :
represent(value)
;
}
public String toString(real value) {
return
Real.isNaN(value) ? "NaN" :
value == Real.POSITIVE_INFINITY ? "Infinity" :
value == Real.NEGATIVE_INFINITY ? "-Infinity" :
new String(represent(value))
;
}
public boolean orderAll { read = fldOrdAll }
public boolean orderSign { read = fldOrdSign }
public boolean significandAll { read = fldSigAll }
public boolean significandSign { read = fldSigSign }
public boolean exponentialForm { read = fldExpForm }
public int orderDigits { read = fldOrdDigits }
public int significandDigits { read = fldSigDigits }
protected real parse(CharArray string) {
int length = string == null ? 0 : string.length;
if(0 >= length)
{
throw new NumberFormatException(avt.lang.package.getResourceString("illegal-argument.number-format"));
}
boolean negative = false;
int frac = 0;
int order = 0;
int index = 0;
long2 intValue = 0;
switch(string[0])
{
case '-':
negative = true;
/* падение через */
case '+':
case ' ':
if(++index >= length)
{
throw new NumberFormatException(avt.lang.package.getResourceString("illegal-argument.number-format"));
}
}
char character = string[index];
if((character < '0' || character > '9') && character != '.')
{
throw new NumberFormatException(avt.lang.package.getResourceString("illegal-argument.number-format"));
}
if(character != '.') for(intValue = character - '0'; ++index < length && (character = string[index]) >= '0' && character <= '9'; )
{
long2 digit = character - '0';
long2 temp = Int128.mul(intValue, 10);
if(Int128.compare(intValue, MUL_MIN) > 0 || Int128.compare(temp, Int128.sub(Int128.MAX_VALUE, digit)) > 0)
{
frac--;
} else
{
intValue = Int128.add(temp, digit);
}
}
if(index < length && string[index] == '.') while(++index < length && (character = string[index]) >= '0' && character <= '9')
{
long2 digit = character - '0';
long2 temp = Int128.mul(intValue, 10);
if(Int128.compare(intValue, MUL_MIN) <= 0 && Int128.compare(temp, Int128.sub(Int128.MAX_VALUE, digit)) <= 0)
{
frac++;
intValue = Int128.add(temp, digit);
}
}
if(Int128.signum(intValue) > 0) while(frac > 0 && Int128.signum(Int128.rem(intValue, 10)) == 0)
{
frac--;
intValue = Int128.div(intValue, 10);
}
real result = Int128.toReal(intValue);
if(negative)
{
negative = false;
result /= -1;
}
if(index < length && ((character = string[index]) == 'E' || character == 'e'))
{
if(++index >= length)
{
throw new NumberFormatException(avt.lang.package.getResourceString("illegal-argument.number-format"));
}
switch(string[index])
{
case '-':
negative = true;
/* падение через */
case '+':
if(++index >= length)
{
throw new NumberFormatException(avt.lang.package.getResourceString("illegal-argument.number-format"));
}
}
if((character = string[index]) < '0' || character > '9')
{
throw new NumberFormatException(avt.lang.package.getResourceString("illegal-argument.number-format"));
}
for(order = character - '0'; ++index < length && (character = string[index]) >= '0' && character <= '9'; ) if((order = 10 * order + character - '0') > 9999)
{
throw new NumberFormatException(avt.lang.package.getResourceString("illegal-argument.number-format"));
}
if(negative) order = -order;
}
if(index < length)
{
throw new NumberFormatException(avt.lang.package.getResourceString("illegal-argument.number-format"));
}
return pow10(result, order - frac);
}
protected char[] represent(real value) {
char[] result = new char[32];
Array.fill(result, 0, 32, '0');
long2 bits = Real.toLong2Bits(value);
int length = 0;
int order = (int) bits[1];
if(order < 0)
{
result[length++] = '-';
value /= -1;
}
else if(fldSigSign)
{
result[length++] = '+';
}
if((bits & new short2 { -1, 0x7fff }) == 0)
{
result[length + 1] = '.';
length += fldSigAll ? fldSigDigits + 1 : 3;
if(fldExpForm)
{
result[length++] = 'E';
if(fldOrdSign) result[length++] = '+';
length += fldOrdAll ? fldOrdDigits : 1;
}
} else
{
order = (int) floor(log10(value));
int sigDigits = fldSigDigits;
real minValue = pow10(1, sigDigits < 6 ? -sigDigits : -6);
boolean expForm = fldExpForm || value < minValue || value >= fldLimitValueWithoutExponent;
long2 intValue;
int dotIndex;
if(expForm)
{
intValue = round(pow10(value, sigDigits - order - 1));
if(Int128.compare(intValue, fldMinRepresentValue) < 0)
{
intValue = Int128.mul(intValue, 10);
order--;
}
if(Int128.compare(intValue, fldMaxRepresentValue) > 0)
{
intValue = Int128.div(intValue, 10);
order++;
}
dotIndex = length + 1;
}
else if(value < 1)
{
intValue = round(pow10(value, sigDigits - 1));
dotIndex = length + 1;
}
else if(value < fldLimitValueWithFractialPart)
{
intValue = round(pow10(value, sigDigits - order - 1));
if(Int128.compare(intValue, fldMinRepresentValue) < 0)
{
intValue = Int128.mul(intValue, 10);
order--;
}
if(Int128.compare(intValue, fldMaxRepresentValue) > 0)
{
intValue = Int128.div(intValue, 10);
order++;
}
dotIndex = length + order + 1;
}
else
{
intValue = round(value);
long2 maxValue = fldMaxRepresentValue;
if(Int128.compare(intValue, maxValue) > 0)
{
intValue = maxValue;
}
dotIndex = length + sigDigits;
}
result[dotIndex] = '.';
for(int index = length + sigDigits; index-- > length; intValue = Int128.div(intValue, 10))
{
result[index < dotIndex ? index : index + 1] = (char) ((int) Int128.rem(intValue, 10) + '0');
}
length += sigDigits + 1;
if(!fldSigAll) for(; ; )
{
char character = result[length - 1];
if(character != '0' && character != '.') break;
length--;
if(character == '.')
{
length += 2;
break;
}
}
if(expForm)
{
result[length++] = 'E';
if(order < 0)
{
result[length++] = '-';
order = -order;
}
else if(fldOrdSign)
{
result[length++] = '+';
}
int ordDigits = fldOrdAll ? fldOrdDigits : 1;
if(ordDigits == 1 && order >= 10) ordDigits++;
if(ordDigits == 2 && order >= 100) ordDigits++;
if(ordDigits == 3 && order >= 1000) ordDigits++;
int ordLength = length + ordDigits;
for(int index = ordLength; index-- > length; order /= 10)
{
result[index] = (char) (order % 10 + '0');
}
length = ordLength;
}
}
result.length = length;
return result;
}
}