Skip to content

Commit ea12472

Browse files
committed
intN
1 parent 4614b1f commit ea12472

File tree

1 file changed

+199
-16
lines changed

1 file changed

+199
-16
lines changed

kscr-core/Std/Numeric.cs

Lines changed: 199 additions & 16 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
}
@@ -26,14 +26,14 @@ public sealed class Numeric : IObject
2626
{
2727
Mutable = false,
2828
Bytes = BitConverter.GetBytes((byte)0),
29-
Mode = NumericMode.Byte
29+
Mode = NumericMode.Int
3030
};
3131

3232
public static readonly Numeric One = new(1)
3333
{
3434
Mutable = false,
3535
Bytes = BitConverter.GetBytes((byte)1),
36-
Mode = NumericMode.Byte
36+
Mode = NumericMode.Int
3737
};
3838

3939
private static readonly ConcurrentDictionary<decimal, Numeric> Cache = new();
@@ -60,12 +60,9 @@ public bool Mutable
6060
private set => _mutable = value;
6161
}
6262

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

0 commit comments

Comments
 (0)