Skip to content

Commit d46e158

Browse files
committed
intN
1 parent a7b9af1 commit d46e158

File tree

1 file changed

+216
-17
lines changed

1 file changed

+216
-17
lines changed

kscr-core/Std/Numeric.cs

Lines changed: 216 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
using System;
22
using System.Collections.Concurrent;
3+
using System.Collections.Generic;
34
using System.Globalization;
5+
using System.Linq;
6+
using System.Numerics;
47
using System.Text.RegularExpressions;
58
using KScr.Core.Exception;
69
using KScr.Core.Model;
@@ -10,10 +13,7 @@ namespace KScr.Core.Std;
1013

1114
public enum NumericMode
1215
{
13-
Byte,
14-
Short,
1516
Int,
16-
Long,
1717
Float,
1818
Double
1919
}
@@ -22,9 +22,19 @@ public sealed class Numeric : NativeObj
2222
{
2323
public static readonly Regex NumberRegex = new(@"([\d]+(i|l|f|d|s|b)?)([.,]([\d]+)(f|d))?");
2424

25-
public static Numeric Zero;
25+
public static readonly Numeric Zero = new(0)
26+
{
27+
Mutable = false,
28+
Bytes = BitConverter.GetBytes((byte)0),
29+
Mode = NumericMode.Int
30+
};
2631

27-
public static Numeric One;
32+
public static readonly Numeric One = new(1)
33+
{
34+
Mutable = false,
35+
Bytes = BitConverter.GetBytes((byte)1),
36+
Mode = NumericMode.Int
37+
};
2838

2939
private static readonly ConcurrentDictionary<decimal, Numeric> Cache = new();
3040

@@ -38,12 +48,15 @@ internal Numeric(RuntimeBase vm, bool constant = false) : base(vm)
3848
_objId = vm.NextObjId();
3949
}
4050

41-
public NumericMode Mode { get; internal set; } = NumericMode.Short;
42-
public byte[] Bytes { get; internal set; } = BitConverter.GetBytes((short)0);
43-
public byte ByteValue => GetAs<byte>();
44-
public short ShortValue => GetAs<short>();
45-
public int IntValue => GetAs<int>();
46-
public long LongValue => GetAs<long>();
51+
public bool Mutable
52+
{
53+
get => !_constant && _mutable;
54+
private set => _mutable = value;
55+
}
56+
57+
public NumericMode Mode { get; private set; } = NumericMode.Int;
58+
public byte[] Bytes { get; private set; } = BitConverter.GetBytes((short)0);
59+
public IntN IntNValue => GetAs<IntN>();
4760
public float FloatValue => GetAs<float>();
4861
public double DoubleValue => GetAs<double>();
4962
public string StringValue => GetAs<string>();
@@ -86,10 +99,7 @@ public override Stack InvokeNative(RuntimeBase vm, Stack stack, string member, p
8699
else delta = (Constant(vm, 0.001).Value as Numeric)!;
87100
stack[StackOutput.Default] = Mode switch
88101
{
89-
NumericMode.Byte => ByteValue == other.ByteValue,
90-
NumericMode.Short => ShortValue == other.ShortValue,
91102
NumericMode.Int => IntValue == other.IntValue,
92-
NumericMode.Long => LongValue == other.LongValue,
93103
NumericMode.Float => Math.Abs(FloatValue - other.FloatValue) < delta.FloatValue,
94104
NumericMode.Double => Math.Abs(DoubleValue - other.DoubleValue) < delta.DoubleValue,
95105
_ => throw new ArgumentOutOfRangeException()
@@ -110,10 +120,7 @@ public override string GetKey()
110120
{
111121
return Mode switch
112122
{
113-
NumericMode.Byte => CreateKey(LongValue),
114-
NumericMode.Short => CreateKey(LongValue),
115123
NumericMode.Int => CreateKey(LongValue),
116-
NumericMode.Long => CreateKey(LongValue),
117124
NumericMode.Float => CreateKey(FloatValue),
118125
NumericMode.Double => CreateKey(DoubleValue),
119126
_ => throw new ArgumentOutOfRangeException()
@@ -728,4 +735,196 @@ public IObjectRef Tan(RuntimeBase vm)
728735
throw new ArgumentOutOfRangeException();
729736
}
730737
}
738+
}
739+
740+
public sealed class IntN : IObject
741+
{
742+
public static readonly char[] digits = new[] {
743+
'0',
744+
'1',
745+
'2',
746+
'3',
747+
'4',
748+
'5',
749+
'6',
750+
'7',
751+
'8',
752+
'9'
753+
};
754+
public static readonly char[] chars = new[] {
755+
'A',
756+
'B',
757+
'C',
758+
'D',
759+
'E',
760+
'F',
761+
'G',
762+
'H',
763+
'I',
764+
'J',
765+
'K',
766+
'L',
767+
'M',
768+
'N',
769+
'O',
770+
'P',
771+
'Q',
772+
'R',
773+
'S',
774+
'T',
775+
'U',
776+
'V',
777+
'W',
778+
'X',
779+
'Y',
780+
'Z',
781+
'a',
782+
'b',
783+
'c',
784+
'd',
785+
'e',
786+
'f',
787+
'g',
788+
'h',
789+
'i',
790+
'j',
791+
'k',
792+
'l',
793+
'm',
794+
'n',
795+
'o',
796+
'p',
797+
'q',
798+
'r',
799+
's',
800+
't',
801+
'u',
802+
'v',
803+
'w',
804+
'x',
805+
'y',
806+
'z'
807+
};
808+
809+
private static readonly Dictionary<int, IClassInstance> _clsInsts = new();
810+
private readonly IClassInstance _clsInst;
811+
812+
public readonly int N;
813+
public readonly byte[] Bytes;
814+
815+
private byte[] Bits
816+
{
817+
get
818+
{
819+
byte[] bits = new byte[N];
820+
for (int i = 0; i < N; i++)
821+
bits[i] = (byte)((Bytes[i / 8] & (1 << i % 8 - 1)) != 0 ? 1 : 0);
822+
bits = bits.Reverse().ToArray();
823+
return bits;
824+
}
825+
}
826+
827+
public byte ByteValue
828+
{
829+
get => Bytes[0];
830+
set => Set(new[] { value });
831+
}
832+
833+
public short ShortValue
834+
{
835+
get => BitConverter.ToInt16(Bytes);
836+
set => Set(BitConverter.GetBytes(value));
837+
}
838+
839+
public int IntValue
840+
{
841+
get => BitConverter.ToInt32(Bytes);
842+
set => Set(BitConverter.GetBytes(value));
843+
}
844+
845+
public long LongValue
846+
{
847+
get => BitConverter.ToInt64(Bytes);
848+
set => Set(BitConverter.GetBytes(value));
849+
}
850+
851+
public BigInteger BitIntValue
852+
{
853+
get => new(Bytes);
854+
set => Set(value.ToByteArray());
855+
}
856+
857+
public string StringValue(byte radix)
858+
{ // todo: inspect
859+
string str = string.Empty;
860+
if (radix == 1)
861+
str = string.Join("", Bits.Select(x => x.ToString()));
862+
else
863+
{
864+
(int div, int mod) divmod(int x, int y) => (x / y, x % y);
865+
void add(int[] output, int[] input)
866+
{
867+
int carry = 0;
868+
for (int i = 0; i < input.Length; i++)
869+
(carry, output[i]) = divmod(output[i] + input[i] + carry, radix);
870+
for (int i = 0; carry > 0; i++)
871+
(carry, output[i]) = divmod(output[i] + carry, radix);
872+
}
873+
874+
int[] res = new int[(int)Math.Ceiling(str.Length * Math.Log(2) / Math.Log(10))],
875+
s = StringValue(1).Substring(2).Select(x => (int)x).ToArray();
876+
foreach (var c in s)
877+
{
878+
add(res, res);
879+
add(res, new[] { c });
880+
}
881+
882+
str = string.Join("", res.Reverse().Select(x => (char)x).ToArray());
883+
}
884+
return radix switch
885+
{
886+
1 => "0b" + str,
887+
16 => "0x" + str,
888+
_ => (radix == 10 ? string.Empty : "0_") + str
889+
};
890+
}
891+
892+
public IntN(RuntimeBase vm, int n = 32)
893+
{
894+
if (n / 8 > chars.Length)
895+
throw new FatalException($"n too large: {n} ({n / 8})");
896+
N = n;
897+
Bytes = new byte[(int)Math.Ceiling((double)n / 8)];
898+
ObjectId = vm.NextObjId();
899+
_clsInst = GetClsInst(vm, n);
900+
}
901+
902+
private void Set(byte[] bytes)
903+
{
904+
if (bytes.Length > N)
905+
throw new ArgumentOutOfRangeException(nameof(bytes.Length), bytes.Length, "Set value too large");
906+
Array.Fill(Bytes, (byte)0);
907+
Array.Copy(bytes, 0, Bytes, N - bytes.Length, bytes.Length);
908+
}
909+
910+
public long ObjectId { get; }
911+
912+
public IClassInstance Type => _clsInst;
913+
914+
public string ToString(short variant) => StringValue((byte)(variant == 0 ? 10 : variant));
915+
916+
public Stack Invoke(RuntimeBase vm, Stack stack, string member, params IObject?[] args)
917+
{
918+
throw new NotImplementedException();
919+
}
920+
921+
public string GetKey() => $"int<{N}>: {StringValue(16)}";
922+
923+
private IClassInstance GetClsInst(RuntimeBase vm, int n)
924+
{
925+
if (_clsInsts.ContainsKey(n))
926+
return _clsInsts[n];
927+
return _clsInsts[n] = Class.IntType.CreateInstance(vm, Class.IntType,
928+
new TypeParameter(N.ToString(), TypeParameterSpecializationType.N));
929+
}
731930
}

0 commit comments

Comments
 (0)