├── .gitignore
├── FixedPointSharp.sln
├── FixedPointSharp
├── FixedPointSharp.csproj
├── LUT
│ ├── AsinLut.cs
│ ├── SinCosLut.cs
│ ├── SinLut.cs
│ └── TanLut.cs
├── Random.cs
├── fbool.cs
├── fixlut.cs
├── fixmath.cs
├── fixmath2.cs
├── fixmath3.cs
├── fixmath4.cs
├── fp.cs
├── fp2.cs
├── fp3.cs
└── fp4.cs
├── LICENSE
├── LUTGenerator
├── Data.cs
├── Generator.cs
├── LUTGenerator.csproj
├── Properties
│ └── AssemblyInfo.cs
└── Writer.cs
├── README.md
└── UnitTests
├── FP_Tests.cs
├── FP_fixmath3Tests.cs
├── FP_fixmathTests.cs
├── FP_randomTests.cs
├── UnitTests.csproj
└── plotting.cs
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/
2 | bin/
3 | obj/
4 | FixedPointSharp.sln.DotSettings.user
5 |
--------------------------------------------------------------------------------
/FixedPointSharp.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FixedPointSharp", "FixedPointSharp\FixedPointSharp.csproj", "{20E87959-A8C3-4526-8415-3656D19E6C49}"
4 | EndProject
5 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTests", "UnitTests\UnitTests.csproj", "{69F2B676-5D86-47AA-8DC7-996219496F2C}"
6 | EndProject
7 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LUTGenerator", "LUTGenerator\LUTGenerator.csproj", "{49D328B2-A15B-42A7-9C16-B04E160FE7B3}"
8 | EndProject
9 | Global
10 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
11 | Debug|Any CPU = Debug|Any CPU
12 | Release|Any CPU = Release|Any CPU
13 | EndGlobalSection
14 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
15 | {20E87959-A8C3-4526-8415-3656D19E6C49}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
16 | {20E87959-A8C3-4526-8415-3656D19E6C49}.Debug|Any CPU.Build.0 = Debug|Any CPU
17 | {20E87959-A8C3-4526-8415-3656D19E6C49}.Release|Any CPU.ActiveCfg = Release|Any CPU
18 | {20E87959-A8C3-4526-8415-3656D19E6C49}.Release|Any CPU.Build.0 = Release|Any CPU
19 | {69F2B676-5D86-47AA-8DC7-996219496F2C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
20 | {69F2B676-5D86-47AA-8DC7-996219496F2C}.Debug|Any CPU.Build.0 = Debug|Any CPU
21 | {69F2B676-5D86-47AA-8DC7-996219496F2C}.Release|Any CPU.ActiveCfg = Release|Any CPU
22 | {69F2B676-5D86-47AA-8DC7-996219496F2C}.Release|Any CPU.Build.0 = Release|Any CPU
23 | {49D328B2-A15B-42A7-9C16-B04E160FE7B3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
24 | {49D328B2-A15B-42A7-9C16-B04E160FE7B3}.Debug|Any CPU.Build.0 = Debug|Any CPU
25 | {49D328B2-A15B-42A7-9C16-B04E160FE7B3}.Release|Any CPU.ActiveCfg = Release|Any CPU
26 | {49D328B2-A15B-42A7-9C16-B04E160FE7B3}.Release|Any CPU.Build.0 = Release|Any CPU
27 | EndGlobalSection
28 | EndGlobal
29 |
--------------------------------------------------------------------------------
/FixedPointSharp/FixedPointSharp.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.1
5 | true
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/FixedPointSharp/LUT/SinCosLut.cs:
--------------------------------------------------------------------------------
1 | namespace Deterministic.FixedPoint {
2 | public static partial class fixlut {
3 | public static readonly int[] SinCosLut = {
4 | 0, 65536, 804, 65531, 1608, 65516, 2412, 65492, 3216, 65457,
5 | 4019, 65413, 4821, 65358, 5623, 65294, 6424, 65220, 7224, 65137,
6 | 8022, 65043, 8820, 64940, 9616, 64827, 10411, 64704, 11204, 64571,
7 | 11996, 64429, 12785, 64277, 13573, 64115, 14359, 63944, 15143, 63763,
8 | 15924, 63572, 16703, 63372, 17479, 63162, 18253, 62943, 19024, 62714,
9 | 19792, 62476, 20557, 62228, 21320, 61971, 22078, 61705, 22834, 61429,
10 | 23586, 61145, 24335, 60851, 25080, 60547, 25821, 60235, 26558, 59914,
11 | 27291, 59583, 28020, 59244, 28745, 58896, 29466, 58538, 30182, 58172,
12 | 30893, 57798, 31600, 57414, 32303, 57022, 33000, 56621, 33692, 56212,
13 | 34380, 55794, 35062, 55368, 35738, 54934, 36410, 54491, 37076, 54040,
14 | 37736, 53581, 38391, 53114, 39040, 52639, 39683, 52156, 40320, 51665,
15 | 40951, 51166, 41576, 50660, 42194, 50146, 42806, 49624, 43412, 49095,
16 | 44011, 48559, 44604, 48015, 45190, 47464, 45769, 46906, 46341, 46341,
17 | 46906, 45769, 47464, 45190, 48015, 44604, 48559, 44011, 49095, 43412,
18 | 49624, 42806, 50146, 42194, 50660, 41576, 51166, 40951, 51665, 40320,
19 | 52156, 39683, 52639, 39040, 53114, 38391, 53581, 37736, 54040, 37076,
20 | 54491, 36410, 54934, 35738, 55368, 35062, 55794, 34380, 56212, 33692,
21 | 56621, 33000, 57022, 32303, 57414, 31600, 57798, 30893, 58172, 30182,
22 | 58538, 29466, 58896, 28745, 59244, 28020, 59583, 27291, 59914, 26558,
23 | 60235, 25821, 60547, 25080, 60851, 24335, 61145, 23586, 61429, 22834,
24 | 61705, 22078, 61971, 21320, 62228, 20557, 62476, 19792, 62714, 19024,
25 | 62943, 18253, 63162, 17479, 63372, 16703, 63572, 15924, 63763, 15143,
26 | 63944, 14359, 64115, 13573, 64277, 12785, 64429, 11996, 64571, 11204,
27 | 64704, 10411, 64827, 9616, 64940, 8820, 65043, 8022, 65137, 7224,
28 | 65220, 6424, 65294, 5623, 65358, 4821, 65413, 4019, 65457, 3216,
29 | 65492, 2412, 65516, 1608, 65531, 804, 65536, 0, 65531, -804,
30 | 65516, -1608, 65492, -2412, 65457, -3216, 65413, -4019, 65358, -4821,
31 | 65294, -5623, 65220, -6424, 65137, -7224, 65043, -8022, 64940, -8820,
32 | 64827, -9616, 64704, -10411, 64571, -11204, 64429, -11996, 64277, -12785,
33 | 64115, -13573, 63944, -14359, 63763, -15143, 63572, -15924, 63372, -16703,
34 | 63162, -17479, 62943, -18253, 62714, -19024, 62476, -19792, 62228, -20557,
35 | 61971, -21320, 61705, -22078, 61429, -22834, 61145, -23586, 60851, -24335,
36 | 60547, -25080, 60235, -25821, 59914, -26558, 59583, -27291, 59244, -28020,
37 | 58896, -28745, 58538, -29466, 58172, -30182, 57798, -30893, 57414, -31600,
38 | 57022, -32303, 56621, -33000, 56212, -33692, 55794, -34380, 55368, -35062,
39 | 54934, -35738, 54491, -36410, 54040, -37076, 53581, -37736, 53114, -38391,
40 | 52639, -39040, 52156, -39683, 51665, -40320, 51166, -40951, 50660, -41576,
41 | 50146, -42194, 49624, -42806, 49095, -43412, 48559, -44011, 48015, -44604,
42 | 47464, -45190, 46906, -45769, 46341, -46341, 45769, -46906, 45190, -47464,
43 | 44604, -48015, 44011, -48559, 43412, -49095, 42806, -49624, 42194, -50146,
44 | 41576, -50660, 40951, -51166, 40320, -51665, 39683, -52156, 39040, -52639,
45 | 38391, -53114, 37736, -53581, 37076, -54040, 36410, -54491, 35738, -54934,
46 | 35062, -55368, 34380, -55794, 33692, -56212, 33000, -56621, 32303, -57022,
47 | 31600, -57414, 30893, -57798, 30182, -58172, 29466, -58538, 28745, -58896,
48 | 28020, -59244, 27291, -59583, 26558, -59914, 25821, -60235, 25080, -60547,
49 | 24335, -60851, 23586, -61145, 22834, -61429, 22078, -61705, 21320, -61971,
50 | 20557, -62228, 19792, -62476, 19024, -62714, 18253, -62943, 17479, -63162,
51 | 16703, -63372, 15924, -63572, 15143, -63763, 14359, -63944, 13573, -64115,
52 | 12785, -64277, 11996, -64429, 11204, -64571, 10411, -64704, 9616, -64827,
53 | 8820, -64940, 8022, -65043, 7224, -65137, 6424, -65220, 5623, -65294,
54 | 4821, -65358, 4019, -65413, 3216, -65457, 2412, -65492, 1608, -65516,
55 | 804, -65531, 0, -65536, -804, -65531, -1608, -65516, -2412, -65492,
56 | -3216, -65457, -4019, -65413, -4821, -65358, -5623, -65294, -6424, -65220,
57 | -7224, -65137, -8022, -65043, -8820, -64940, -9616, -64827, -10411, -64704,
58 | -11204, -64571, -11996, -64429, -12785, -64277, -13573, -64115, -14359, -63944,
59 | -15143, -63763, -15924, -63572, -16703, -63372, -17479, -63162, -18253, -62943,
60 | -19024, -62714, -19792, -62476, -20557, -62228, -21320, -61971, -22078, -61705,
61 | -22834, -61429, -23586, -61145, -24335, -60851, -25080, -60547, -25821, -60235,
62 | -26558, -59914, -27291, -59583, -28020, -59244, -28745, -58896, -29466, -58538,
63 | -30182, -58172, -30893, -57798, -31600, -57414, -32303, -57022, -33000, -56621,
64 | -33692, -56212, -34380, -55794, -35062, -55368, -35738, -54934, -36410, -54491,
65 | -37076, -54040, -37736, -53581, -38391, -53114, -39040, -52639, -39683, -52156,
66 | -40320, -51665, -40951, -51166, -41576, -50660, -42194, -50146, -42806, -49624,
67 | -43412, -49095, -44011, -48559, -44604, -48015, -45190, -47464, -45769, -46906,
68 | -46341, -46341, -46906, -45769, -47464, -45190, -48015, -44604, -48559, -44011,
69 | -49095, -43412, -49624, -42806, -50146, -42194, -50660, -41576, -51166, -40951,
70 | -51665, -40320, -52156, -39683, -52639, -39040, -53114, -38391, -53581, -37736,
71 | -54040, -37076, -54491, -36410, -54934, -35738, -55368, -35062, -55794, -34380,
72 | -56212, -33692, -56621, -33000, -57022, -32303, -57414, -31600, -57798, -30893,
73 | -58172, -30182, -58538, -29466, -58896, -28745, -59244, -28020, -59583, -27291,
74 | -59914, -26558, -60235, -25821, -60547, -25080, -60851, -24335, -61145, -23586,
75 | -61429, -22834, -61705, -22078, -61971, -21320, -62228, -20557, -62476, -19792,
76 | -62714, -19024, -62943, -18253, -63162, -17479, -63372, -16703, -63572, -15924,
77 | -63763, -15143, -63944, -14359, -64115, -13573, -64277, -12785, -64429, -11996,
78 | -64571, -11204, -64704, -10411, -64827, -9616, -64940, -8820, -65043, -8022,
79 | -65137, -7224, -65220, -6424, -65294, -5623, -65358, -4821, -65413, -4019,
80 | -65457, -3216, -65492, -2412, -65516, -1608, -65531, -804, -65536, 0,
81 | -65531, 804, -65516, 1608, -65492, 2412, -65457, 3216, -65413, 4019,
82 | -65358, 4821, -65294, 5623, -65220, 6424, -65137, 7224, -65043, 8022,
83 | -64940, 8820, -64827, 9616, -64704, 10411, -64571, 11204, -64429, 11996,
84 | -64277, 12785, -64115, 13573, -63944, 14359, -63763, 15143, -63572, 15924,
85 | -63372, 16703, -63162, 17479, -62943, 18253, -62714, 19024, -62476, 19792,
86 | -62228, 20557, -61971, 21320, -61705, 22078, -61429, 22834, -61145, 23586,
87 | -60851, 24335, -60547, 25080, -60235, 25821, -59914, 26558, -59583, 27291,
88 | -59244, 28020, -58896, 28745, -58538, 29466, -58172, 30182, -57798, 30893,
89 | -57414, 31600, -57022, 32303, -56621, 33000, -56212, 33692, -55794, 34380,
90 | -55368, 35062, -54934, 35738, -54491, 36410, -54040, 37076, -53581, 37736,
91 | -53114, 38391, -52639, 39040, -52156, 39683, -51665, 40320, -51166, 40951,
92 | -50660, 41576, -50146, 42194, -49624, 42806, -49095, 43412, -48559, 44011,
93 | -48015, 44604, -47464, 45190, -46906, 45769, -46341, 46341, -45769, 46906,
94 | -45190, 47464, -44604, 48015, -44011, 48559, -43412, 49095, -42806, 49624,
95 | -42194, 50146, -41576, 50660, -40951, 51166, -40320, 51665, -39683, 52156,
96 | -39040, 52639, -38391, 53114, -37736, 53581, -37076, 54040, -36410, 54491,
97 | -35738, 54934, -35062, 55368, -34380, 55794, -33692, 56212, -33000, 56621,
98 | -32303, 57022, -31600, 57414, -30893, 57798, -30182, 58172, -29466, 58538,
99 | -28745, 58896, -28020, 59244, -27291, 59583, -26558, 59914, -25821, 60235,
100 | -25080, 60547, -24335, 60851, -23586, 61145, -22834, 61429, -22078, 61705,
101 | -21320, 61971, -20557, 62228, -19792, 62476, -19024, 62714, -18253, 62943,
102 | -17479, 63162, -16703, 63372, -15924, 63572, -15143, 63763, -14359, 63944,
103 | -13573, 64115, -12785, 64277, -11996, 64429, -11204, 64571, -10411, 64704,
104 | -9616, 64827, -8820, 64940, -8022, 65043, -7224, 65137, -6424, 65220,
105 | -5623, 65294, -4821, 65358, -4019, 65413, -3216, 65457, -2412, 65492,
106 | -1608, 65516, -804, 65531, 0, 65536
107 | };
108 | }
109 | }
--------------------------------------------------------------------------------
/FixedPointSharp/LUT/SinLut.cs:
--------------------------------------------------------------------------------
1 | namespace Deterministic.FixedPoint {
2 | public static partial class fixlut {
3 | public static readonly int[] SinLut = {
4 | 0, 804, 1608, 2412, 3216, 4019, 4821, 5623, 6424, 7224,
5 | 8022, 8820, 9616, 10411, 11204, 11996, 12785, 13573, 14359, 15143,
6 | 15924, 16703, 17479, 18253, 19024, 19792, 20557, 21320, 22078, 22834,
7 | 23586, 24335, 25080, 25821, 26558, 27291, 28020, 28745, 29466, 30182,
8 | 30893, 31600, 32303, 33000, 33692, 34380, 35062, 35738, 36410, 37076,
9 | 37736, 38391, 39040, 39683, 40320, 40951, 41576, 42194, 42806, 43412,
10 | 44011, 44604, 45190, 45769, 46341, 46906, 47464, 48015, 48559, 49095,
11 | 49624, 50146, 50660, 51166, 51665, 52156, 52639, 53114, 53581, 54040,
12 | 54491, 54934, 55368, 55794, 56212, 56621, 57022, 57414, 57798, 58172,
13 | 58538, 58896, 59244, 59583, 59914, 60235, 60547, 60851, 61145, 61429,
14 | 61705, 61971, 62228, 62476, 62714, 62943, 63162, 63372, 63572, 63763,
15 | 63944, 64115, 64277, 64429, 64571, 64704, 64827, 64940, 65043, 65137,
16 | 65220, 65294, 65358, 65413, 65457, 65492, 65516, 65531, 65536, 65531,
17 | 65516, 65492, 65457, 65413, 65358, 65294, 65220, 65137, 65043, 64940,
18 | 64827, 64704, 64571, 64429, 64277, 64115, 63944, 63763, 63572, 63372,
19 | 63162, 62943, 62714, 62476, 62228, 61971, 61705, 61429, 61145, 60851,
20 | 60547, 60235, 59914, 59583, 59244, 58896, 58538, 58172, 57798, 57414,
21 | 57022, 56621, 56212, 55794, 55368, 54934, 54491, 54040, 53581, 53114,
22 | 52639, 52156, 51665, 51166, 50660, 50146, 49624, 49095, 48559, 48015,
23 | 47464, 46906, 46341, 45769, 45190, 44604, 44011, 43412, 42806, 42194,
24 | 41576, 40951, 40320, 39683, 39040, 38391, 37736, 37076, 36410, 35738,
25 | 35062, 34380, 33692, 33000, 32303, 31600, 30893, 30182, 29466, 28745,
26 | 28020, 27291, 26558, 25821, 25080, 24335, 23586, 22834, 22078, 21320,
27 | 20557, 19792, 19024, 18253, 17479, 16703, 15924, 15143, 14359, 13573,
28 | 12785, 11996, 11204, 10411, 9616, 8820, 8022, 7224, 6424, 5623,
29 | 4821, 4019, 3216, 2412, 1608, 804, 0, -804, -1608, -2412,
30 | -3216, -4019, -4821, -5623, -6424, -7224, -8022, -8820, -9616, -10411,
31 | -11204, -11996, -12785, -13573, -14359, -15143, -15924, -16703, -17479, -18253,
32 | -19024, -19792, -20557, -21320, -22078, -22834, -23586, -24335, -25080, -25821,
33 | -26558, -27291, -28020, -28745, -29466, -30182, -30893, -31600, -32303, -33000,
34 | -33692, -34380, -35062, -35738, -36410, -37076, -37736, -38391, -39040, -39683,
35 | -40320, -40951, -41576, -42194, -42806, -43412, -44011, -44604, -45190, -45769,
36 | -46341, -46906, -47464, -48015, -48559, -49095, -49624, -50146, -50660, -51166,
37 | -51665, -52156, -52639, -53114, -53581, -54040, -54491, -54934, -55368, -55794,
38 | -56212, -56621, -57022, -57414, -57798, -58172, -58538, -58896, -59244, -59583,
39 | -59914, -60235, -60547, -60851, -61145, -61429, -61705, -61971, -62228, -62476,
40 | -62714, -62943, -63162, -63372, -63572, -63763, -63944, -64115, -64277, -64429,
41 | -64571, -64704, -64827, -64940, -65043, -65137, -65220, -65294, -65358, -65413,
42 | -65457, -65492, -65516, -65531, -65536, -65531, -65516, -65492, -65457, -65413,
43 | -65358, -65294, -65220, -65137, -65043, -64940, -64827, -64704, -64571, -64429,
44 | -64277, -64115, -63944, -63763, -63572, -63372, -63162, -62943, -62714, -62476,
45 | -62228, -61971, -61705, -61429, -61145, -60851, -60547, -60235, -59914, -59583,
46 | -59244, -58896, -58538, -58172, -57798, -57414, -57022, -56621, -56212, -55794,
47 | -55368, -54934, -54491, -54040, -53581, -53114, -52639, -52156, -51665, -51166,
48 | -50660, -50146, -49624, -49095, -48559, -48015, -47464, -46906, -46341, -45769,
49 | -45190, -44604, -44011, -43412, -42806, -42194, -41576, -40951, -40320, -39683,
50 | -39040, -38391, -37736, -37076, -36410, -35738, -35062, -34380, -33692, -33000,
51 | -32303, -31600, -30893, -30182, -29466, -28745, -28020, -27291, -26558, -25821,
52 | -25080, -24335, -23586, -22834, -22078, -21320, -20557, -19792, -19024, -18253,
53 | -17479, -16703, -15924, -15143, -14359, -13573, -12785, -11996, -11204, -10411,
54 | -9616, -8820, -8022, -7224, -6424, -5623, -4821, -4019, -3216, -2412,
55 | -1608, -804, 0
56 | };
57 | }
58 | }
--------------------------------------------------------------------------------
/FixedPointSharp/LUT/TanLut.cs:
--------------------------------------------------------------------------------
1 | namespace Deterministic.FixedPoint {
2 | public static partial class fixlut {
3 | public static readonly int[] TanLut = {
4 | 0, 804, 1609, 2414, 3220, 4026, 4834, 5644, 6455, 7268,
5 | 8083, 8901, 9721, 10545, 11372, 12202, 13036, 13874, 14717, 15564,
6 | 16416, 17273, 18136, 19005, 19880, 20762, 21650, 22546, 23449, 24360,
7 | 25280, 26208, 27146, 28093, 29050, 30018, 30996, 31986, 32988, 34002,
8 | 35030, 36071, 37126, 38196, 39281, 40382, 41500, 42636, 43790, 44963,
9 | 46156, 47369, 48605, 49863, 51145, 52451, 53784, 55144, 56532, 57950,
10 | 59398, 60880, 62395, 63947, 65536, 67165, 68835, 70548, 72308, 74116,
11 | 75974, 77887, 79856, 81885, 83977, 86135, 88365, 90670, 93054, 95523,
12 | 98082, 100736, 103493, 106358, 109340, 112447, 115687, 119071, 122609, 126314,
13 | 130198, 134276, 138564, 143081, 147847, 152884, 158218, 163878, 169896, 176309,
14 | 183161, 190499, 198380, 206870, 216043, 225990, 236817, 248648, 261634, 275959,
15 | 291845, 309568, 329472, 351993, 377693, 407305, 441808, 482534, 531352, 590958,
16 | 665398, 761030, 888450, 1066730, 1334016, 1779314, 2669641, 5340086, -2147483648, -5340086,
17 | -2669641, -1779314, -1334016, -1066730, -888450, -761030, -665398, -590958, -531352, -482534,
18 | -441808, -407305, -377693, -351993, -329472, -309568, -291845, -275959, -261634, -248648,
19 | -236817, -225990, -216043, -206870, -198380, -190499, -183161, -176309, -169896, -163878,
20 | -158218, -152884, -147847, -143081, -138564, -134276, -130198, -126314, -122609, -119071,
21 | -115687, -112447, -109340, -106358, -103493, -100736, -98082, -95523, -93054, -90670,
22 | -88365, -86135, -83977, -81885, -79856, -77887, -75974, -74116, -72308, -70548,
23 | -68835, -67165, -65536, -63947, -62395, -60880, -59398, -57950, -56532, -55144,
24 | -53784, -52451, -51145, -49863, -48605, -47369, -46156, -44963, -43790, -42636,
25 | -41500, -40382, -39281, -38196, -37126, -36071, -35030, -34002, -32988, -31986,
26 | -30996, -30018, -29050, -28093, -27146, -26208, -25280, -24360, -23449, -22546,
27 | -21650, -20762, -19880, -19005, -18136, -17273, -16416, -15564, -14717, -13874,
28 | -13036, -12202, -11372, -10545, -9721, -8901, -8083, -7268, -6455, -5644,
29 | -4834, -4026, -3220, -2414, -1609, -804, 0, 804, 1609, 2414,
30 | 3220, 4026, 4834, 5644, 6455, 7268, 8083, 8901, 9721, 10545,
31 | 11372, 12202, 13036, 13874, 14717, 15564, 16416, 17273, 18136, 19005,
32 | 19880, 20762, 21650, 22546, 23449, 24360, 25280, 26208, 27146, 28093,
33 | 29050, 30018, 30996, 31986, 32988, 34002, 35030, 36071, 37126, 38196,
34 | 39281, 40382, 41500, 42636, 43790, 44963, 46156, 47369, 48605, 49863,
35 | 51145, 52451, 53784, 55144, 56532, 57950, 59398, 60880, 62395, 63947,
36 | 65536, 67165, 68835, 70548, 72308, 74116, 75974, 77887, 79856, 81885,
37 | 83977, 86135, 88365, 90670, 93054, 95523, 98082, 100736, 103493, 106358,
38 | 109340, 112447, 115687, 119071, 122609, 126314, 130198, 134276, 138564, 143081,
39 | 147847, 152884, 158218, 163878, 169896, 176309, 183161, 190499, 198380, 206870,
40 | 216043, 225990, 236817, 248648, 261634, 275959, 291845, 309568, 329472, 351993,
41 | 377693, 407305, 441808, 482534, 531352, 590958, 665398, 761030, 888450, 1066730,
42 | 1334016, 1779314, 2669641, 5340086, -2147483648, -5340086, -2669641, -1779314, -1334016, -1066730,
43 | -888450, -761030, -665398, -590958, -531352, -482534, -441808, -407305, -377693, -351993,
44 | -329472, -309568, -291845, -275959, -261634, -248648, -236817, -225990, -216043, -206870,
45 | -198380, -190499, -183161, -176309, -169896, -163878, -158218, -152884, -147847, -143081,
46 | -138564, -134276, -130198, -126314, -122609, -119071, -115687, -112447, -109340, -106358,
47 | -103493, -100736, -98082, -95523, -93054, -90670, -88365, -86135, -83977, -81885,
48 | -79856, -77887, -75974, -74116, -72308, -70548, -68835, -67165, -65536, -63947,
49 | -62395, -60880, -59398, -57950, -56532, -55144, -53784, -52451, -51145, -49863,
50 | -48605, -47369, -46156, -44963, -43790, -42636, -41500, -40382, -39281, -38196,
51 | -37126, -36071, -35030, -34002, -32988, -31986, -30996, -30018, -29050, -28093,
52 | -27146, -26208, -25280, -24360, -23449, -22546, -21650, -20762, -19880, -19005,
53 | -18136, -17273, -16416, -15564, -14717, -13874, -13036, -12202, -11372, -10545,
54 | -9721, -8901, -8083, -7268, -6455, -5644, -4834, -4026, -3220, -2414,
55 | -1609, -804, 0
56 | };
57 | }
58 | }
--------------------------------------------------------------------------------
/FixedPointSharp/Random.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.CompilerServices;
2 | using System.Runtime.InteropServices;
3 |
4 | namespace Deterministic.FixedPoint {
5 | [StructLayout(LayoutKind.Explicit, Size = SIZE)]
6 | public struct Random {
7 | public const int SIZE = 4;
8 |
9 | [FieldOffset(0)]
10 | public uint state;
11 |
12 | ///
13 | /// Seed must be non-zero
14 | ///
15 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
16 | public Random(uint seed)
17 | {
18 | state = seed;
19 | NextState();
20 | }
21 |
22 | ///
23 | /// Seed must be non-zero
24 | ///
25 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
26 | public void SetState(uint seed)
27 | {
28 | state = seed;
29 | NextState();
30 | }
31 |
32 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
33 | private uint NextState() {
34 | var t = state;
35 | state ^= state << 13;
36 | state ^= state >> 17;
37 | state ^= state << 5;
38 | return t;
39 | }
40 |
41 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
42 | public bool NextBool()
43 | {
44 | return (NextState() & 1) == 1;
45 | }
46 |
47 | /// Returns value in range [-2147483647, 2147483647]
48 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
49 | public int NextInt()
50 | {
51 | return (int)NextState() ^ -2147483648;
52 | }
53 |
54 | /// Returns value in range [0, max]
55 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
56 | public int NextInt(int max)
57 | {
58 | return (int)((NextState() * (ulong)max) >> 32);
59 | }
60 |
61 | /// Returns value in range [min, max].
62 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
63 | public int NextInt(int min, int max)
64 | {
65 | var range = (uint)(max - min);
66 | return (int)(NextState() * (ulong)range >> 32) + min;
67 | }
68 |
69 | /// Returns value in range [0, 1]
70 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
71 | public fp NextFp() {
72 | return new fp(NextInt(0, 65535));
73 | }
74 |
75 | /// Returns vector with all components in range [0, 1]
76 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
77 | public fp2 NextFp2() {
78 | return new fp2(NextFp(), NextFp());
79 | }
80 |
81 | /// Returns vector with all components in range [0, 1]
82 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
83 | public fp3 NextFp3() {
84 | return new fp3(NextFp(), NextFp(), NextFp());
85 | }
86 |
87 | /// Returns vector with all components in range [0, 1]
88 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
89 | public fp4 NextFp4() {
90 | return new fp4(NextFp(), NextFp(), NextFp(), NextFp());
91 | }
92 |
93 |
94 | /// Returns value in range [0, max]
95 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
96 | public fp NextFp(fp max) {
97 | return NextFp() * max;
98 | }
99 |
100 | /// Returns vector with all components in range [0, max]
101 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
102 | public fp2 NextFp2(fp2 max) {
103 | return NextFp2() * max;
104 | }
105 |
106 | /// Returns vector with all components in range [0, max]
107 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
108 | public fp3 NextFp3(fp3 max) {
109 | return NextFp3() * max;
110 | }
111 |
112 | /// Returns vector with all components in range [0, max]
113 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
114 | public fp4 NextFp4(fp4 max) {
115 | return NextFp4() * max;
116 | }
117 |
118 | /// Returns value in range [min, max]
119 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
120 | public fp NextFp(fp min, fp max) {
121 | return NextFp() * (max - min) + min;
122 | }
123 |
124 | /// Returns vector with all components in range [min, max]
125 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
126 | public fp2 NextFp2(fp2 min, fp2 max) {
127 | return NextFp2() * (max - min) + min;
128 | }
129 |
130 | /// Returns vector with all components in range [min, max]
131 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
132 | public fp3 NextFp3(fp3 min, fp3 max) {
133 | return NextFp3() * (max - min) + min;
134 | }
135 |
136 | /// Returns vector with all components in range [min, max]
137 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
138 | public fp4 NextFp4(fp4 min, fp4 max) {
139 | return NextFp4() * (max - min) + min;
140 | }
141 |
142 | /// Returns a normalized 2D direction
143 | public fp2 NextDirection2D() {
144 | var angle = NextFp() * fp.pi * fp._2;
145 | fixmath.SinCos(angle, out var sin, out var cos);
146 | return new fp2(sin,cos);
147 | }
148 |
149 | /// Returns a normalized 3D direction
150 | public fp3 NextDirection3D() {
151 | var z = NextFp(fp._2) - fp._1;
152 | var r = fixmath.Sqrt(fixmath.Max(fp._1 - z * z, fp._0));
153 | var angle = NextFp(fp.pi2);
154 | fixmath.SinCos(angle, out var sin, out var cos);
155 | return new fp3(cos * r, sin * r, z);
156 | }
157 | }
158 | }
--------------------------------------------------------------------------------
/FixedPointSharp/fbool.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.InteropServices;
2 |
3 | namespace Deterministic.FixedPoint {
4 | [StructLayout(LayoutKind.Explicit, Size = SIZE)]
5 | // ReSharper disable once InconsistentNaming
6 | public struct fbool {
7 | public const int SIZE = 2;
8 |
9 | [FieldOffset(0)]
10 | public ushort Value;
11 |
12 | public static implicit operator bool(fbool b)
13 | {
14 | return b.Value > 0;
15 | }
16 |
17 | public static implicit operator fbool(bool b)
18 | {
19 | fbool fbool;
20 | fbool.Value = (ushort) (b ? 1 : 0);
21 | return fbool;
22 | }
23 |
24 | public bool Equals(fbool other) {
25 | return Value == other.Value;
26 | }
27 |
28 | public override bool Equals(object obj) {
29 | return obj is fbool other && Equals(other);
30 | }
31 |
32 | public static bool operator ==(fbool left, fbool right) {
33 | return left.Value == right.Value;
34 | }
35 |
36 | public static bool operator !=(fbool left, fbool right) {
37 | return left.Value != right.Value;
38 | }
39 |
40 | public override int GetHashCode() {
41 | return Value;
42 | }
43 |
44 | public override string ToString() {
45 | return ((bool) this).ToString();
46 | }
47 | }
48 | }
--------------------------------------------------------------------------------
/FixedPointSharp/fixlut.cs:
--------------------------------------------------------------------------------
1 | namespace Deterministic.FixedPoint {
2 | public static partial class fixlut {
3 | public const int FRACTIONS_COUNT = 5;
4 | public const int PRECISION = 16;
5 | public const int SHIFT = 16 - 9;
6 | public const long PI = 205887L;
7 | public const long ONE = 1 << PRECISION;
8 | public const long HALF = 1 << (PRECISION-1);
9 | public const long ZERO = 0;
10 |
11 |
12 | public static long sin(long value) {
13 | var sign = 1;
14 | if (value < 0) {
15 | value = -value;
16 | sign = -1;
17 | }
18 |
19 | var index = (int) (value >> SHIFT);
20 | var fraction = (value - (index << SHIFT)) << 9;
21 | var a = SinLut[index];
22 | var b = SinLut[index + 1];
23 | var v2 = a + (((b - a) * fraction) >> PRECISION);
24 | return v2 * sign;
25 | }
26 |
27 | public static long cos(long value) {
28 | if (value < 0) {
29 | value = -value;
30 | }
31 |
32 | value += fp._0_25.value;
33 |
34 | if (value >= 65536) {
35 | value -= 65536;
36 | }
37 |
38 | var index = (int) (value >> SHIFT);
39 | var fraction = (value - (index << SHIFT)) << 9;
40 | var a = SinLut[index];
41 | var b = SinLut[index + 1];
42 | var v2 = a + (((b - a) * fraction) >> PRECISION);
43 | return v2;
44 | }
45 |
46 |
47 | public static long tan(long value) {
48 | var sign = 1;
49 |
50 | if (value < 0) {
51 | value = -value;
52 | sign = -1;
53 | }
54 |
55 | var index = (int) (value >> SHIFT);
56 | var fraction = (value - (index << SHIFT)) << 9;
57 | var a = TanLut[index];
58 | var b = TanLut[index + 1];
59 | var v2 = a + (((b - a) * fraction) >> PRECISION);
60 | return v2 * sign;
61 | }
62 |
63 | public static void sin_cos(long value, out long sin, out long cos) {
64 | var sign = 1;
65 | if (value < 0) {
66 | value = -value;
67 | sign = -1;
68 | }
69 |
70 | var index = (int) (value >> SHIFT);
71 | var doubleIndex = index * 2;
72 | var fractions = (value - (index << SHIFT)) << 9;
73 |
74 | var sinA = SinCosLut[doubleIndex];
75 | var cosA = SinCosLut[doubleIndex + 1];
76 | var sinB = SinCosLut[doubleIndex + 2];
77 | var cosB = SinCosLut[doubleIndex + 3];
78 |
79 | sin = (sinA + (((sinB - sinA) * fractions) >> PRECISION)) * sign;
80 | cos = cosA + (((cosB - cosA) * fractions) >> PRECISION);
81 | }
82 |
83 | public static long asin(long value) {
84 | bool flag = false;
85 | if (value < 0) {
86 | flag = true;
87 | value = -value;
88 | }
89 |
90 | var result = AsinLut[value];
91 | if (flag)
92 | result = -result;
93 | return result;
94 | }
95 |
96 | public static long acos(long value) {
97 | bool flag = false;
98 | if (value < 0) {
99 | flag = true;
100 | value = -value;
101 | }
102 |
103 | long result = -AsinLut[value];
104 | if (flag)
105 | result = -result;
106 |
107 | result += fp.pi_half.value;
108 | return result;
109 | }
110 | }
111 | }
--------------------------------------------------------------------------------
/FixedPointSharp/fixmath.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.CompilerServices;
2 |
3 | namespace Deterministic.FixedPoint {
4 | public partial struct fixmath {
5 | private static readonly fp _atan2Number1 = new fp(-883);
6 | private static readonly fp _atan2Number2 = new fp(3767);
7 | private static readonly fp _atan2Number3 = new fp(7945);
8 | private static readonly fp _atan2Number4 = new fp(12821);
9 | private static readonly fp _atan2Number5 = new fp(21822);
10 | private static readonly fp _atan2Number6 = new fp(65536);
11 | private static readonly fp _atan2Number7 = new fp(102943);
12 | private static readonly fp _atan2Number8 = new fp(205887);
13 | private static readonly fp _atanApproximatedNumber1 = new fp(16036);
14 | private static readonly fp _atanApproximatedNumber2 = new fp(4345);
15 | private static readonly byte[] _bsrLookup = {0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30, 8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31};
16 |
17 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
18 | public static int BitScanReverse(uint num) {
19 | num |= num >> 1;
20 | num |= num >> 2;
21 | num |= num >> 4;
22 | num |= num >> 8;
23 | num |= num >> 16;
24 | return _bsrLookup[(num * 0x07C4ACDDU) >> 27];
25 | }
26 |
27 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
28 | public static int CountLeadingZeroes(uint num) {
29 | return num == 0 ? 32 : BitScanReverse(num) ^ 31;
30 | }
31 |
32 | /// Angle in radians
33 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
34 | public static fp Sin(fp num) {
35 | num.value %= fp.pi2.value;
36 | num *= fp.one_div_pi2;
37 | var raw = fixlut.sin(num.value);
38 | fp result;
39 | result.value = raw;
40 | return result;
41 | }
42 |
43 | /// Angle in radians
44 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
45 | public static fp Cos(fp num) {
46 | num.value %= fp.pi2.value;
47 | num *= fp.one_div_pi2;
48 | return new fp(fixlut.cos(num.value));
49 | }
50 |
51 | /// Angle in radians
52 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
53 | public static fp Tan(fp num) {
54 | num.value %= fp.pi2.value;
55 | num *= fp.one_div_pi2;
56 | return new fp(fixlut.tan(num.value));
57 | }
58 |
59 | /// Cos [-1, 1]
60 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
61 | public static fp Acos(fp num) {
62 | return new fp(fixlut.acos(num.value));
63 | }
64 |
65 | /// Sin [-1, 1]
66 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
67 | public static fp Asin(fp num) {
68 | return new fp(fixlut.asin(num.value));
69 | }
70 |
71 | /// Tan
72 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
73 | public static fp Atan(fp num) {
74 | return Atan2(num, fp._1);
75 | }
76 |
77 | /// Tan [-1, 1]
78 | /// Max error ~0.0015
79 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
80 | public static fp AtanApproximated(fp num) {
81 | var absX = Abs(num);
82 | return fp.pi_quarter * num - num * (absX - fp._1) * (_atanApproximatedNumber1 + _atanApproximatedNumber2 * absX);
83 | }
84 |
85 | /// Denominator
86 | /// Numerator
87 | public static fp Atan2(fp y, fp x) {
88 | var absX = Abs(x);
89 | var absY = Abs(y);
90 | var t3 = absX;
91 | var t1 = absY;
92 | var t0 = Max(t3, t1);
93 | t1 = Min(t3, t1);
94 | t3 = fp._1 / t0;
95 | t3 = t1 * t3;
96 | var t4 = t3 * t3;
97 | t0 = _atan2Number1;
98 | t0 = t0 * t4 + _atan2Number2;
99 | t0 = t0 * t4 - _atan2Number3;
100 | t0 = t0 * t4 + _atan2Number4;
101 | t0 = t0 * t4 - _atan2Number5;
102 | t0 = t0 * t4 + _atan2Number6;
103 | t3 = t0 * t3;
104 | t3 = absY > absX ? _atan2Number7 - t3 : t3;
105 | t3 = x < fp._0 ? _atan2Number8 - t3 : t3;
106 | t3 = y < fp._0 ? -t3 : t3;
107 | return t3;
108 | }
109 |
110 | /// Angle in radians
111 | public static void SinCos(fp num, out fp sin, out fp cos) {
112 | num.value %= fp.pi2.value;
113 | num *= fp.one_div_pi2;
114 | fixlut.sin_cos(num.value, out var sinVal, out var cosVal);
115 | sin.value = sinVal;
116 | cos.value = cosVal;
117 | }
118 |
119 | public static fp Rcp(fp num) {
120 | //(fp.1 << 16)
121 | return new fp(4294967296 / num.value);
122 | }
123 |
124 | public static fp Rsqrt(fp num) {
125 | //(fp.1 << 16)
126 | return new fp(4294967296 / Sqrt(num).value);
127 | }
128 |
129 | public static fp Sqrt(fp num) {
130 | fp r;
131 |
132 | if (num.value == 0) {
133 | r.value = 0;
134 | }
135 | else {
136 | var b = (num.value >> 1) + 1L;
137 | var c = (b + (num.value / b)) >> 1;
138 |
139 | while (c < b) {
140 | b = c;
141 | c = (b + (num.value / b)) >> 1;
142 | }
143 |
144 | r.value = b << (fixlut.PRECISION >> 1);
145 | }
146 |
147 | return r;
148 | }
149 |
150 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
151 | public static fp Floor(fp num) {
152 | num.value = num.value >> fixlut.PRECISION << fixlut.PRECISION;
153 | return num;
154 | }
155 |
156 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
157 | public static fp Ceil(fp num) {
158 | var fractions = num.value & 0x000000000000FFFFL;
159 |
160 | if (fractions == 0) {
161 | return num;
162 | }
163 |
164 | num.value = num.value >> fixlut.PRECISION << fixlut.PRECISION;
165 | num.value += fixlut.ONE;
166 | return num;
167 | }
168 |
169 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
170 | public static fp Fractions(fp num) {
171 | return new fp(num.value & 0x000000000000FFFFL);
172 | }
173 |
174 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
175 | public static int RoundToInt(fp num) {
176 | var fraction = num.value & 0x000000000000FFFFL;
177 |
178 | if (fraction >= fixlut.HALF) {
179 | return num.AsInt + 1;
180 | }
181 |
182 | return num.AsInt;
183 | }
184 |
185 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
186 | public static fp Min(fp a, fp b) {
187 | return a.value < b.value ? a : b;
188 | }
189 |
190 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
191 | public static int Min(int a, int b) {
192 | return a < b ? a : b;
193 | }
194 |
195 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
196 | public static long Min(long a, long b) {
197 | return a < b ? a : b;
198 | }
199 |
200 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
201 | public static fp Max(fp a, fp b) {
202 | return a.value > b.value ? a : b;
203 | }
204 |
205 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
206 | public static int Max(int a, int b) {
207 | return a > b ? a : b;
208 | }
209 |
210 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
211 | public static long Max(long a, long b) {
212 | return a > b ? a : b;
213 | }
214 |
215 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
216 | public static fp Abs(fp num) {
217 | return new fp(num.value < 0 ? -num.value : num.value);
218 | }
219 |
220 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
221 | public static fp Clamp(fp num, fp min, fp max) {
222 | if (num.value < min.value) {
223 | return min;
224 | }
225 |
226 | if (num.value > max.value) {
227 | return max;
228 | }
229 |
230 | return num;
231 | }
232 |
233 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
234 | public static int Clamp(int num, int min, int max) {
235 | return num < min ? min : num > max ? max : num;
236 | }
237 |
238 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
239 | public static long Clamp(long num, long min, long max) {
240 | return num < min ? min : num > max ? max : num;
241 | }
242 |
243 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
244 | public static fp Clamp01(fp num) {
245 | if (num.value < 0) {
246 | return fp._0;
247 | }
248 |
249 | return num.value > fp._1.value ? fp._1 : num;
250 | }
251 |
252 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
253 | public static fp Lerp(fp from, fp to, fp t) {
254 | t = Clamp01(t);
255 | return from + (to - from) * t;
256 | }
257 |
258 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
259 | public static fbool Lerp(fbool from, fbool to, fp t) {
260 | return t.value > fp._0_50.value ? to : from;
261 | }
262 |
263 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
264 | public static fp Repeat(fp value, fp length) {
265 | return Clamp(value - Floor(value / length) * length, 0, length);
266 | }
267 |
268 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
269 | public static fp LerpAngle(fp from, fp to, fp t) {
270 | var num = Repeat(to - from, fp.pi2);
271 | return Lerp(from, from + (num > fp.pi ? num - fp.pi2 : num), t);
272 | }
273 |
274 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
275 | public static fp NormalizeRadians(fp angle) {
276 | angle.value %= fixlut.PI;
277 | return angle;
278 | }
279 |
280 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
281 | public static fp LerpUnclamped(fp from, fp to, fp t) {
282 | return from + (to - from) * t;
283 | }
284 |
285 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
286 | public static fp Sign(fp num) {
287 | return num.value < fixlut.ZERO ? fp.minus_one : fp._1;
288 | }
289 |
290 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
291 | public static bool IsOppositeSign(fp a, fp b) {
292 | return ((a.value ^ b.value) < 0);
293 | }
294 |
295 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
296 | public static fp SetSameSign(fp target, fp reference) {
297 | return IsOppositeSign(target, reference) ? target * fp.minus_one : target;
298 | }
299 |
300 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
301 | public static fp Pow2(int power) {
302 | return new fp(fixlut.ONE << power);
303 | }
304 |
305 | public static fp Exp(fp num) {
306 | if (num == fp._0) return fp._1;
307 | if (num == fp._1) return fp.e;
308 | if (num.value >= 2097152) return fp.max;
309 | if (num.value <= -786432) return fp._0;
310 |
311 | var neg = num.value < 0;
312 | if (neg) num = -num;
313 |
314 | var result = num + fp._1;
315 | var term = num;
316 |
317 | for (var i = 2; i < 30; i++) {
318 | term *= num / (fp)i;
319 | result += term;
320 |
321 | if (term.value < 500 && ((i > 15) || (term.value < 20)))
322 | break;
323 | }
324 |
325 | if (neg) result = fp._1 / result;
326 |
327 | return result;
328 | }
329 | }
330 | }
--------------------------------------------------------------------------------
/FixedPointSharp/fixmath2.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.CompilerServices;
2 |
3 | namespace Deterministic.FixedPoint
4 | {
5 | public partial struct fixmath
6 | {
7 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
8 | public static fp Sum(fp2 v) {
9 | return new fp(v.x.value + v.y.value);
10 | }
11 |
12 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
13 | public static fp2 Min(fp2 a, fp2 b)
14 | {
15 | var ret = a.x.value < b.x.value ? a.x : b.x;
16 | var ret1 = a.y.value < b.y.value ? a.y : b.y;
17 |
18 | return new fp2(ret, ret1);
19 | }
20 |
21 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
22 | public static fp2 Max(fp2 a, fp2 b)
23 | {
24 | var ret = a.x.value > b.x.value ? a.x : b.x;
25 | var ret1 = a.y.value > b.y.value ? a.y : b.y;
26 | return new fp2(ret, ret1);
27 | }
28 |
29 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
30 | public static fp Dot(fp2 a, fp2 b)
31 | {
32 | a.x.value = ((a.x.value * b.x.value) >> fixlut.PRECISION) + ((a.y.value * b.y.value) >> fixlut.PRECISION);
33 | return a.x;
34 | }
35 |
36 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
37 | public static fp Cross(fp2 a, fp2 b) {
38 | a.x.value = (a.x.value * b.y.value >> fixlut.PRECISION) - (a.y.value * b.x.value >> fixlut.PRECISION);
39 | return a.x;
40 | }
41 |
42 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
43 | public static fp2 Cross(fp2 a, fp s)
44 | {
45 | return new fp2(s * a.y, -s * a.x);
46 | }
47 |
48 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
49 | public static fp2 Cross(fp s, fp2 a) {
50 | fp2 result;
51 | result.x.value = -s.value * a.y.value >> fixlut.PRECISION;
52 | result.y.value = s.value * a.x.value >> fixlut.PRECISION;
53 | return result;
54 | }
55 |
56 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
57 | public static fp2 Clamp(fp2 num, fp2 min, fp2 max)
58 | {
59 | fp2 r;
60 |
61 | if (num.x.value < min.x.value)
62 | {
63 | r.x = min.x;
64 | }
65 | else {
66 | r.x = num.x.value > max.x.value ? max.x : num.x;
67 | }
68 |
69 | if (num.y.value < min.y.value)
70 | {
71 | r.y = min.y;
72 | }
73 | else {
74 | r.y = num.y.value > max.y.value ? max.y : num.y;
75 | }
76 |
77 | return r;
78 | }
79 |
80 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
81 | public static fp2 ClampMagnitude(fp2 v, fp length)
82 | {
83 | fp2 value = v;
84 | fp r;
85 |
86 | r.value =
87 | ((value.x.value * value.x.value) >> fixlut.PRECISION) +
88 | ((value.y.value * value.y.value) >> fixlut.PRECISION);
89 | if (r.value <= ((length.value * length.value) >> fixlut.PRECISION))
90 | {
91 | }
92 | else
93 | {
94 | fp2 v1 = value;
95 | fp m = default;
96 | fp r2;
97 |
98 | r2.value =
99 | ((v1.x.value * v1.x.value) >> fixlut.PRECISION) +
100 | ((v1.y.value * v1.y.value) >> fixlut.PRECISION);
101 | fp r1;
102 |
103 | if (r2.value == 0)
104 | {
105 | r1.value = 0;
106 | }
107 | else
108 | {
109 | var b = (r2.value >> 1) + 1L;
110 | var c = (b + (r2.value / b)) >> 1;
111 |
112 | while (c < b)
113 | {
114 | b = c;
115 | c = (b + (r2.value / b)) >> 1;
116 | }
117 |
118 | r1.value = b << (fixlut.PRECISION >> 1);
119 | }
120 |
121 | m = r1;
122 |
123 | if (m.value <= fp.epsilon.value)
124 | {
125 | v1 = default;
126 | }
127 | else
128 | {
129 | v1.x.value = ((v1.x.value << fixlut.PRECISION) / m.value);
130 | v1.y.value = ((v1.y.value << fixlut.PRECISION) / m.value);
131 | }
132 |
133 | value = v1 * length;
134 | }
135 |
136 | return value;
137 | }
138 |
139 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
140 | public static fp Magnitude(fp2 v)
141 | {
142 | fp r;
143 |
144 | r.value =
145 | ((v.x.value * v.x.value) >> fixlut.PRECISION) +
146 | ((v.y.value * v.y.value) >> fixlut.PRECISION);
147 | fp r1;
148 |
149 | if (r.value == 0)
150 | {
151 | r1.value = 0;
152 | }
153 | else
154 | {
155 | var b = (r.value >> 1) + 1L;
156 | var c = (b + (r.value / b)) >> 1;
157 |
158 | while (c < b)
159 | {
160 | b = c;
161 | c = (b + (r.value / b)) >> 1;
162 | }
163 |
164 | r1.value = b << (fixlut.PRECISION >> 1);
165 | }
166 |
167 | return r1;
168 | }
169 |
170 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
171 | public static fp MagnitudeSqr(fp2 v)
172 | {
173 | v.x.value =
174 | ((v.x.value * v.x.value) >> fixlut.PRECISION) +
175 | ((v.y.value * v.y.value) >> fixlut.PRECISION);
176 |
177 | return v.x;
178 | }
179 |
180 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
181 | public static fp Distance(fp2 a, fp2 b)
182 | {
183 | fp2 v;
184 |
185 | v.x.value = a.x.value - b.x.value;
186 | v.y.value = a.y.value - b.y.value;
187 |
188 | fp r;
189 |
190 | r.value =
191 | ((v.x.value * v.x.value) >> fixlut.PRECISION) +
192 | ((v.y.value * v.y.value) >> fixlut.PRECISION);
193 | fp r1;
194 |
195 | if (r.value == 0)
196 | {
197 | r1.value = 0;
198 | }
199 | else
200 | {
201 | var b1 = (r.value >> 1) + 1L;
202 | var c = (b1 + (r.value / b1)) >> 1;
203 |
204 | while (c < b1)
205 | {
206 | b1 = c;
207 | c = (b1 + (r.value / b1)) >> 1;
208 | }
209 |
210 | r1.value = b1 << (fixlut.PRECISION >> 1);
211 | }
212 |
213 | return r1;
214 | }
215 |
216 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
217 | public static fp DistanceSqr(fp2 a, fp2 b)
218 | {
219 | var x = a.x.value - b.x.value;
220 | var z = a.y.value - b.y.value;
221 |
222 | a.x.value = ((x * x) >> fixlut.PRECISION) + ((z * z) >> fixlut.PRECISION);
223 | return a.x;
224 | }
225 |
226 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
227 | public static fp2 Normalize(fp2 v)
228 | {
229 | fp2 v1 = v;
230 | fp m = default;
231 | fp r;
232 |
233 | r.value =
234 | ((v1.x.value * v1.x.value) >> fixlut.PRECISION) +
235 | ((v1.y.value * v1.y.value) >> fixlut.PRECISION);
236 | fp r1;
237 |
238 | if (r.value == 0)
239 | {
240 | r1.value = 0;
241 | }
242 | else
243 | {
244 | var b = (r.value >> 1) + 1L;
245 | var c = (b + (r.value / b)) >> 1;
246 |
247 | while (c < b)
248 | {
249 | b = c;
250 | c = (b + (r.value / b)) >> 1;
251 | }
252 |
253 | r1.value = b << (fixlut.PRECISION >> 1);
254 | }
255 |
256 | m = r1;
257 |
258 | if (m.value <= fp.epsilon.value)
259 | {
260 | v1 = default;
261 | }
262 | else
263 | {
264 | v1.x.value = ((v1.x.value << fixlut.PRECISION) / m.value);
265 | v1.y.value = ((v1.y.value << fixlut.PRECISION) / m.value);
266 | }
267 |
268 | return v1;
269 | }
270 |
271 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
272 | public static fp2 Normalize(fp2 v, out fp magnitude)
273 | {
274 | if (v == fp2.zero)
275 | {
276 | magnitude = fp._0;
277 | return fp2.zero;
278 | }
279 |
280 | magnitude = Magnitude(v);
281 | return v / magnitude;
282 | }
283 |
284 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
285 | public static fp2 Lerp(fp2 from, fp2 to, fp t) {
286 | t = Clamp01(t);
287 | return new fp2(LerpUnclamped(from.x, to.x, t), LerpUnclamped(from.y, to.y, t));
288 | }
289 |
290 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
291 | public static fp2 LerpUnclamped(fp2 from, fp2 to, fp t)
292 | {
293 | return new fp2(LerpUnclamped(from.x, to.x, t), LerpUnclamped(from.y, to.y, t));
294 | }
295 |
296 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
297 | public static fp Angle(fp2 a, fp2 b)
298 | {
299 | fp2 v = a;
300 | fp m = default;
301 | fp r2;
302 |
303 | r2.value =
304 | ((v.x.value * v.x.value) >> fixlut.PRECISION) +
305 | ((v.y.value * v.y.value) >> fixlut.PRECISION);
306 | fp r1;
307 |
308 | if (r2.value == 0)
309 | {
310 | r1.value = 0;
311 | }
312 | else
313 | {
314 | var b2 = (r2.value >> 1) + 1L;
315 | var c = (b2 + (r2.value / b2)) >> 1;
316 |
317 | while (c < b2)
318 | {
319 | b2 = c;
320 | c = (b2 + (r2.value / b2)) >> 1;
321 | }
322 |
323 | r1.value = b2 << (fixlut.PRECISION >> 1);
324 | }
325 |
326 | m = r1;
327 |
328 | if (m.value <= fp.epsilon.value)
329 | {
330 | v = default;
331 | }
332 | else
333 | {
334 | v.x.value = ((v.x.value << fixlut.PRECISION) / m.value);
335 | v.y.value = ((v.y.value << fixlut.PRECISION) / m.value);
336 | }
337 |
338 | fp2 v1 = b;
339 | fp m1 = default;
340 | fp r3;
341 |
342 | r3.value =
343 | ((v1.x.value * v1.x.value) >> fixlut.PRECISION) +
344 | ((v1.y.value * v1.y.value) >> fixlut.PRECISION);
345 | fp r4;
346 |
347 | if (r3.value == 0)
348 | {
349 | r4.value = 0;
350 | }
351 | else
352 | {
353 | var b3 = (r3.value >> 1) + 1L;
354 | var c1 = (b3 + (r3.value / b3)) >> 1;
355 |
356 | while (c1 < b3)
357 | {
358 | b3 = c1;
359 | c1 = (b3 + (r3.value / b3)) >> 1;
360 | }
361 |
362 | r4.value = b3 << (fixlut.PRECISION >> 1);
363 | }
364 |
365 | m1 = r4;
366 |
367 | if (m1.value <= fp.epsilon.value)
368 | {
369 | v1 = default;
370 | }
371 | else
372 | {
373 | v1.x.value = ((v1.x.value << fixlut.PRECISION) / m1.value);
374 | v1.y.value = ((v1.y.value << fixlut.PRECISION) / m1.value);
375 | }
376 |
377 | fp2 a1 = v;
378 | fp2 b1 = v1;
379 | var x = ((a1.x.value * b1.x.value) >> fixlut.PRECISION);
380 | var z = ((a1.y.value * b1.y.value) >> fixlut.PRECISION);
381 |
382 | fp r;
383 |
384 | r.value = x + z;
385 | var dot = r;
386 | fp min = -fp._1;
387 | fp max = +fp._1;
388 | fp ret;
389 | if (dot.value < min.value)
390 | {
391 | ret = min;
392 | }
393 | else {
394 | ret = dot.value > max.value ? max : dot;
395 | }
396 |
397 | return new fp(fixlut.acos(ret.value)) * fp.rad2deg;
398 | }
399 |
400 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
401 | public static fp Radians(fp2 a, fp2 b)
402 | {
403 | fp2 v = a;
404 | fp m = default;
405 | fp r2;
406 |
407 | r2.value =
408 | ((v.x.value * v.x.value) >> fixlut.PRECISION) +
409 | ((v.y.value * v.y.value) >> fixlut.PRECISION);
410 | fp r1;
411 |
412 | if (r2.value == 0)
413 | {
414 | r1.value = 0;
415 | }
416 | else
417 | {
418 | var b2 = (r2.value >> 1) + 1L;
419 | var c = (b2 + (r2.value / b2)) >> 1;
420 |
421 | while (c < b2)
422 | {
423 | b2 = c;
424 | c = (b2 + (r2.value / b2)) >> 1;
425 | }
426 |
427 | r1.value = b2 << (fixlut.PRECISION >> 1);
428 | }
429 |
430 | m = r1;
431 |
432 | if (m.value <= fp.epsilon.value)
433 | {
434 | v = default;
435 | }
436 | else
437 | {
438 | v.x.value = ((v.x.value << fixlut.PRECISION) / m.value);
439 | v.y.value = ((v.y.value << fixlut.PRECISION) / m.value);
440 | }
441 |
442 | fp2 v1 = b;
443 | fp m1 = default;
444 | fp r3;
445 |
446 | r3.value =
447 | ((v1.x.value * v1.x.value) >> fixlut.PRECISION) +
448 | ((v1.y.value * v1.y.value) >> fixlut.PRECISION);
449 | fp r4;
450 |
451 | if (r3.value == 0)
452 | {
453 | r4.value = 0;
454 | }
455 | else
456 | {
457 | var b3 = (r3.value >> 1) + 1L;
458 | var c1 = (b3 + (r3.value / b3)) >> 1;
459 |
460 | while (c1 < b3)
461 | {
462 | b3 = c1;
463 | c1 = (b3 + (r3.value / b3)) >> 1;
464 | }
465 |
466 | r4.value = b3 << (fixlut.PRECISION >> 1);
467 | }
468 |
469 | m1 = r4;
470 |
471 | if (m1.value <= fp.epsilon.value)
472 | {
473 | v1 = default;
474 | }
475 | else
476 | {
477 | v1.x.value = ((v1.x.value << fixlut.PRECISION) / m1.value);
478 | v1.y.value = ((v1.y.value << fixlut.PRECISION) / m1.value);
479 | }
480 |
481 | fp2 a1 = v;
482 | fp2 b1 = v1;
483 | var x = ((a1.x.value * b1.x.value) >> fixlut.PRECISION);
484 | var z = ((a1.y.value * b1.y.value) >> fixlut.PRECISION);
485 |
486 | fp r;
487 |
488 | r.value = x + z;
489 | var dot = r;
490 | fp min = -fp._1;
491 | fp max = +fp._1;
492 | fp ret;
493 | if (dot.value < min.value)
494 | {
495 | ret = min;
496 | }
497 | else
498 | {
499 | if (dot.value > max.value)
500 | {
501 | ret = max;
502 | }
503 | else
504 | {
505 | ret = dot;
506 | }
507 | }
508 |
509 | return new fp(fixlut.acos(ret.value));
510 | }
511 |
512 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
513 | public static fp RadiansSigned(fp2 a, fp2 b)
514 | {
515 | fp2 v = a;
516 | fp m = default;
517 | fp r2;
518 |
519 | r2.value =
520 | ((v.x.value * v.x.value) >> fixlut.PRECISION) +
521 | ((v.y.value * v.y.value) >> fixlut.PRECISION);
522 | fp r1;
523 |
524 | if (r2.value == 0)
525 | {
526 | r1.value = 0;
527 | }
528 | else
529 | {
530 | var b2 = (r2.value >> 1) + 1L;
531 | var c = (b2 + (r2.value / b2)) >> 1;
532 |
533 | while (c < b2)
534 | {
535 | b2 = c;
536 | c = (b2 + (r2.value / b2)) >> 1;
537 | }
538 |
539 | r1.value = b2 << (fixlut.PRECISION >> 1);
540 | }
541 |
542 | m = r1;
543 |
544 | if (m.value <= fp.epsilon.value)
545 | {
546 | v = default;
547 | }
548 | else
549 | {
550 | v.x.value = ((v.x.value << fixlut.PRECISION) / m.value);
551 | v.y.value = ((v.y.value << fixlut.PRECISION) / m.value);
552 | }
553 |
554 | fp2 v1 = b;
555 | fp m1 = default;
556 | fp r3;
557 |
558 | r3.value =
559 | ((v1.x.value * v1.x.value) >> fixlut.PRECISION) +
560 | ((v1.y.value * v1.y.value) >> fixlut.PRECISION);
561 | fp r4;
562 |
563 | if (r3.value == 0)
564 | {
565 | r4.value = 0;
566 | }
567 | else
568 | {
569 | var b3 = (r3.value >> 1) + 1L;
570 | var c1 = (b3 + (r3.value / b3)) >> 1;
571 |
572 | while (c1 < b3)
573 | {
574 | b3 = c1;
575 | c1 = (b3 + (r3.value / b3)) >> 1;
576 | }
577 |
578 | r4.value = b3 << (fixlut.PRECISION >> 1);
579 | }
580 |
581 | m1 = r4;
582 |
583 | if (m1.value <= fp.epsilon.value)
584 | {
585 | v1 = default;
586 | }
587 | else
588 | {
589 | v1.x.value = ((v1.x.value << fixlut.PRECISION) / m1.value);
590 | v1.y.value = ((v1.y.value << fixlut.PRECISION) / m1.value);
591 | }
592 |
593 | fp2 a1 = v;
594 | fp2 b1 = v1;
595 | var x = ((a1.x.value * b1.x.value) >> fixlut.PRECISION);
596 | var z = ((a1.y.value * b1.y.value) >> fixlut.PRECISION);
597 |
598 | fp r;
599 |
600 | r.value = x + z;
601 | var dot = r;
602 | fp min = -fp._1;
603 | fp max = +fp._1;
604 | fp ret;
605 | if (dot.value < min.value)
606 | {
607 | ret = min;
608 | }
609 | else
610 | {
611 | if (dot.value > max.value)
612 | {
613 | ret = max;
614 | }
615 | else
616 | {
617 | ret = dot;
618 | }
619 | }
620 |
621 | var rad = new fp(fixlut.acos(ret.value));
622 | var sign = ((a.x * b.y - a.y * b.x).value < fixlut.ZERO) ? fp.minus_one : fp._1;
623 |
624 | return rad * sign;
625 | }
626 |
627 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
628 | public static fp RadiansSkipNormalize(fp2 a, fp2 b)
629 | {
630 | fp2 a1 = a;
631 | fp2 b1 = b;
632 | var x = ((a1.x.value * b1.x.value) >> fixlut.PRECISION);
633 | var z = ((a1.y.value * b1.y.value) >> fixlut.PRECISION);
634 |
635 | fp r;
636 |
637 | r.value = x + z;
638 | var dot = r;
639 | fp min = -fp._1;
640 | fp max = +fp._1;
641 | fp ret;
642 | if (dot.value < min.value)
643 | {
644 | ret = min;
645 | }
646 | else {
647 | ret = dot.value > max.value ? max : dot;
648 | }
649 |
650 | return new fp(fixlut.acos(ret.value));
651 | }
652 |
653 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
654 | public static fp RadiansSignedSkipNormalize(fp2 a, fp2 b)
655 | {
656 | fp2 a1 = a;
657 | fp2 b1 = b;
658 | var x = ((a1.x.value * b1.x.value) >> fixlut.PRECISION);
659 | var z = ((a1.y.value * b1.y.value) >> fixlut.PRECISION);
660 |
661 | fp r;
662 |
663 | r.value = x + z;
664 | var dot = r;
665 | fp min = -fp._1;
666 | fp max = +fp._1;
667 | fp ret;
668 | if (dot.value < min.value)
669 | {
670 | ret = min;
671 | }
672 | else
673 | {
674 | if (dot.value > max.value)
675 | {
676 | ret = max;
677 | }
678 | else
679 | {
680 | ret = dot;
681 | }
682 | }
683 |
684 | var rad = new fp(fixlut.acos(ret.value));
685 | var sign = ((a.x * b.y - a.y * b.x).value < fixlut.ZERO) ? fp.minus_one : fp._1;
686 |
687 | return rad * sign;
688 | }
689 |
690 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
691 | public static fp2 Reflect(fp2 vector, fp2 normal)
692 | {
693 | fp dot = (vector.x * normal.x) + (vector.y * normal.y);
694 |
695 | fp2 result;
696 |
697 | result.x = vector.x - ((fp._2 * dot) * normal.x);
698 | result.y = vector.y - ((fp._2 * dot) * normal.y);
699 |
700 | return result;
701 | }
702 |
703 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
704 | public static fp2 Rotate(fp2 vector, fp angle)
705 | {
706 | fp2 vector1 = vector;
707 | var cs = Cos(angle);
708 | var sn = Sin(angle);
709 |
710 | var px = (vector1.x * cs) - (vector1.y * sn);
711 | var pz = (vector1.x * sn) + (vector1.y * cs);
712 |
713 | vector1.x = px;
714 | vector1.y = pz;
715 |
716 | return vector1;
717 | }
718 | }
719 | }
--------------------------------------------------------------------------------
/FixedPointSharp/fixmath3.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.CompilerServices;
2 |
3 | namespace Deterministic.FixedPoint
4 | {
5 | public partial struct fixmath
6 | {
7 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
8 | public static fp Sum(fp3 v) {
9 | return new fp(v.x.value + v.y.value + v.z.value);
10 | }
11 |
12 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
13 | public static fp3 Abs(fp3 v)
14 | {
15 | return new fp3(Abs(v.x), Abs(v.y), Abs(v.z));
16 | }
17 |
18 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
19 | public static fp Dot(fp3 a, fp3 b)
20 | {
21 | return new fp(((a.x.value * b.x.value) >> fixlut.PRECISION) + ((a.y.value * b.y.value) >> fixlut.PRECISION) + ((a.z.value * b.z.value) >> fixlut.PRECISION));
22 | }
23 |
24 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
25 | public static fp3 Cross(fp3 a, fp3 b)
26 | {
27 | fp3 r;
28 |
29 | r.x = a.y * b.z - a.z * b.y;
30 | r.y = a.z * b.x - a.x * b.z;
31 | r.z = a.x * b.y - a.y * b.x;
32 |
33 | return r;
34 | }
35 |
36 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
37 | public static fp Distance(fp3 p1, fp3 p2)
38 | {
39 | fp3 v;
40 | v.x.value = p1.x.value - p2.x.value;
41 | v.y.value = p1.y.value - p2.y.value;
42 | v.z.value = p1.z.value - p2.z.value;
43 |
44 | return Magnitude(v);
45 | }
46 |
47 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
48 | public static fp DistanceSqr(fp3 p1, fp3 p2)
49 | {
50 | fp3 v;
51 | v.x.value = p1.x.value - p2.x.value;
52 | v.y.value = p1.y.value - p2.y.value;
53 | v.z.value = p1.z.value - p2.z.value;
54 |
55 | return MagnitudeSqr(v);
56 | }
57 |
58 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
59 | public static fp3 Lerp(fp3 from, fp3 to, fp t)
60 | {
61 | t = Clamp01(t);
62 | return new fp3(LerpUnclamped(from.x, to.x, t), LerpUnclamped(from.y, to.y, t), LerpUnclamped(from.z, to.z, t));
63 | }
64 |
65 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
66 | public static fp3 LerpUnclamped(fp3 from, fp3 to, fp t)
67 | {
68 | return new fp3(LerpUnclamped(from.x, to.x, t), LerpUnclamped(from.y, to.y, t), LerpUnclamped(from.z, to.z, t));
69 | }
70 |
71 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
72 | public static fp3 Reflect(fp3 vector, fp3 normal)
73 | {
74 | var num = -fp._2 * Dot(normal, vector);
75 | return new fp3(num * normal.x + vector.x, num * normal.y + vector.y, num * normal.z + vector.z);
76 | }
77 |
78 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
79 | public static fp3 Project(fp3 vector, fp3 normal)
80 | {
81 | var sqrMag = MagnitudeSqr(normal);
82 | if (sqrMag < fp.epsilon)
83 | return fp3.zero;
84 |
85 | var dot = Dot(vector, normal);
86 | return normal * dot / sqrMag;
87 | }
88 |
89 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
90 | public static fp3 ProjectOnPlane(fp3 vector, fp3 planeNormal)
91 | {
92 | var sqrMag = MagnitudeSqr(planeNormal);
93 | if (sqrMag < fp.epsilon)
94 | return vector;
95 |
96 | var dot = Dot(vector, planeNormal);
97 | return vector - planeNormal * dot / sqrMag;
98 | }
99 |
100 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
101 | public static fp3 MoveTowards(fp3 current, fp3 target, fp maxDelta)
102 | {
103 | var v = target - current;
104 | var sqrMagnitude = MagnitudeSqr(v);
105 | if (v == fp3.zero || maxDelta >= fp._0 && sqrMagnitude <= maxDelta * maxDelta)
106 | return target;
107 |
108 | var magnitude = Sqrt(sqrMagnitude);
109 | return current + v / magnitude * maxDelta;
110 | }
111 |
112 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
113 | public static fp Angle(fp3 a, fp3 b)
114 | {
115 | var sqr = MagnitudeSqr(a) * MagnitudeSqr(b);
116 | var n = Sqrt(sqr);
117 |
118 | if (n < fp.epsilon)
119 | {
120 | return fp._0;
121 | }
122 |
123 | return Acos(Clamp(Dot(a, b) / n, fp.minus_one, fp._1)) * fp.rad2deg;
124 | }
125 |
126 | public static fp AngleSigned(fp3 a, fp3 b, fp3 axis)
127 | {
128 | var angle = Angle(a, b);
129 | long num2 = ((a.y.value * b.z.value) >> fixlut.PRECISION) - ((a.z.value * b.y.value) >> fixlut.PRECISION);
130 | long num3 = ((a.z.value * b.x.value) >> fixlut.PRECISION) - ((a.x.value * b.z.value) >> fixlut.PRECISION);
131 | long num4 = ((a.x.value * b.y.value) >> fixlut.PRECISION) - ((a.y.value * b.x.value) >> fixlut.PRECISION);
132 | var sign = (((axis.x.value * num2) >> fixlut.PRECISION) +
133 | ((axis.y.value * num3) >> fixlut.PRECISION) +
134 | ((axis.z.value * num4) >> fixlut.PRECISION)) < 0
135 | ? fp.minus_one
136 | : fp._1;
137 | return angle * sign;
138 | }
139 |
140 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
141 | public static fp Radians(fp3 a, fp3 b)
142 | {
143 | return Acos(Clamp(Dot(Normalize(a), Normalize(b)), fp.minus_one, fp._1));
144 | }
145 |
146 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
147 | public static fp RadiansSkipNormalize(fp3 a, fp3 b)
148 | {
149 | return Acos(Clamp(Dot(a, b), fp.minus_one, fp._1));
150 | }
151 |
152 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
153 | public static fp MagnitudeSqr(fp3 v)
154 | {
155 | v.x.value =
156 | ((v.x.value * v.x.value) >> fixlut.PRECISION) +
157 | ((v.y.value * v.y.value) >> fixlut.PRECISION) +
158 | ((v.z.value * v.z.value) >> fixlut.PRECISION);
159 |
160 | return v.x;
161 | }
162 |
163 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
164 | public static fp Magnitude(fp3 v)
165 | {
166 | v.x.value =
167 | ((v.x.value * v.x.value) >> fixlut.PRECISION) +
168 | ((v.y.value * v.y.value) >> fixlut.PRECISION) +
169 | ((v.z.value * v.z.value) >> fixlut.PRECISION);
170 |
171 | return Sqrt(v.x);
172 | }
173 |
174 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
175 | public static fp3 MagnitudeClamp(fp3 v, fp length)
176 | {
177 | var sqrMagnitude = MagnitudeSqr(v);
178 | if (sqrMagnitude <= length * length)
179 | return v;
180 |
181 | var magnitude = Sqrt(sqrMagnitude);
182 | var normalized = v / magnitude;
183 | return normalized * length;
184 | }
185 |
186 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
187 | public static fp3 MagnitudeSet(fp3 v, fp length)
188 | {
189 | return Normalize(v) * length;
190 | }
191 |
192 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
193 | public static fp3 Min(fp3 a, fp3 b)
194 | {
195 | return new fp3(Min(a.x, b.x), Min(a.y, b.y), Min(a.z, b.z));
196 | }
197 |
198 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
199 | public static fp3 Max(fp3 a, fp3 b)
200 | {
201 | return new fp3(Max(a.x, b.x), Max(a.y, b.y), Max(a.z, b.z));
202 | }
203 |
204 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
205 | public static fp3 Normalize(fp3 v)
206 | {
207 | if (v == fp3.zero)
208 | return fp3.zero;
209 |
210 | return v / Magnitude(v);
211 | }
212 |
213 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
214 | public static fp3 Normalize(fp3 v, out fp magnitude)
215 | {
216 | if (v == fp3.zero)
217 | {
218 | magnitude = fp._0;
219 | return fp3.zero;
220 | }
221 |
222 | magnitude = Magnitude(v);
223 | return v / magnitude;
224 | }
225 | }
226 | }
--------------------------------------------------------------------------------
/FixedPointSharp/fixmath4.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.CompilerServices;
2 |
3 | namespace Deterministic.FixedPoint {
4 | public partial struct fixmath
5 | {
6 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
7 | public static fp Sum(fp4 v) {
8 | return new fp(v.x.value + v.y.value + v.z.value + v.w.value);
9 | }
10 |
11 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
12 | public static fp4 Abs(fp4 v)
13 | {
14 | return new fp4(Abs(v.x), Abs(v.y), Abs(v.z), Abs(v.w));
15 | }
16 |
17 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
18 | public static fp Dot(fp4 a, fp4 b) {
19 | return new fp(((a.x.value * b.x.value) >> fixlut.PRECISION) + ((a.y.value * b.y.value) >> fixlut.PRECISION) + ((a.z.value * b.z.value) >> fixlut.PRECISION) +
20 | ((a.w.value * b.w.value) >> fixlut.PRECISION));
21 | }
22 |
23 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
24 | public static fp4 Normalize(fp4 v)
25 | {
26 | if (v == fp4.zero)
27 | return fp4.zero;
28 |
29 | return v / Magnitude(v);
30 | }
31 |
32 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
33 | public static fp4 Normalize(fp4 v, out fp magnitude)
34 | {
35 | if (v == fp4.zero)
36 | {
37 | magnitude = fp._0;
38 | return fp4.zero;
39 | }
40 |
41 | magnitude = Magnitude(v);
42 | return v / magnitude;
43 | }
44 |
45 |
46 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
47 | public static fp Distance(fp4 p1, fp4 p2)
48 | {
49 | fp4 v;
50 | v.x.value = p1.x.value - p2.x.value;
51 | v.y.value = p1.y.value - p2.y.value;
52 | v.z.value = p1.z.value - p2.z.value;
53 | v.w.value = p1.w.value - p2.w.value;
54 |
55 | return Magnitude(v);
56 | }
57 |
58 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
59 | public static fp DistanceSqr(fp4 p1, fp4 p2)
60 | {
61 | fp4 v;
62 | v.x.value = p1.x.value - p2.x.value;
63 | v.y.value = p1.y.value - p2.y.value;
64 | v.z.value = p1.z.value - p2.z.value;
65 | v.w.value = p1.w.value - p2.w.value;
66 |
67 | return MagnitudeSqr(v);
68 | }
69 |
70 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
71 | public static fp MagnitudeSqr(fp4 v)
72 | {
73 | v.x.value =
74 | ((v.x.value * v.x.value) >> fixlut.PRECISION) +
75 | ((v.y.value * v.y.value) >> fixlut.PRECISION) +
76 | ((v.z.value * v.z.value) >> fixlut.PRECISION) +
77 | ((v.w.value * v.w.value) >> fixlut.PRECISION);
78 |
79 | return v.x;
80 | }
81 |
82 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
83 | public static fp Magnitude(fp4 v)
84 | {
85 | v.x.value =
86 | ((v.x.value * v.x.value) >> fixlut.PRECISION) +
87 | ((v.y.value * v.y.value) >> fixlut.PRECISION) +
88 | ((v.z.value * v.z.value) >> fixlut.PRECISION) +
89 | ((v.w.value * v.w.value) >> fixlut.PRECISION);
90 |
91 | return Sqrt(v.x);
92 | }
93 |
94 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
95 | public static fp4 MagnitudeClamp(fp4 v, fp length)
96 | {
97 | var sqrMagnitude = MagnitudeSqr(v);
98 | if (sqrMagnitude <= length * length)
99 | return v;
100 |
101 | var magnitude = Sqrt(sqrMagnitude);
102 | var normalized = v / magnitude;
103 | return normalized * length;
104 | }
105 |
106 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
107 | public static fp4 MagnitudeSet(fp4 v, fp length)
108 | {
109 | return Normalize(v) * length;
110 | }
111 |
112 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
113 | public static fp4 Min(fp4 a, fp4 b)
114 | {
115 | return new fp4(Min(a.x, b.x), Min(a.y, b.y), Min(a.z, b.z), Min(a.w, b.w));
116 | }
117 |
118 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
119 | public static fp4 Max(fp4 a, fp4 b)
120 | {
121 | return new fp4(Max(a.x, b.x), Max(a.y, b.y), Max(a.z, b.z), Max(a.w, b.w));
122 | }
123 | }
124 | }
--------------------------------------------------------------------------------
/FixedPointSharp/fp.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Globalization;
4 | using System.Runtime.CompilerServices;
5 | using System.Runtime.InteropServices;
6 |
7 | namespace Deterministic.FixedPoint {
8 | [Serializable]
9 | [StructLayout(LayoutKind.Explicit, Size = SIZE)]
10 | public struct fp : IEquatable, IComparable {
11 | public const int SIZE = 8;
12 |
13 | public static readonly fp max = new fp(long.MaxValue);
14 | public static readonly fp min = new fp(long.MinValue);
15 | public static readonly fp usable_max = new fp(2147483648L);
16 | public static readonly fp usable_min = -usable_max;
17 |
18 | public static readonly fp _0 = 0;
19 | public static readonly fp _1 = 1;
20 | public static readonly fp _2 = 2;
21 | public static readonly fp _3 = 3;
22 | public static readonly fp _4 = 4;
23 | public static readonly fp _5 = 5;
24 | public static readonly fp _6 = 6;
25 | public static readonly fp _7 = 7;
26 | public static readonly fp _8 = 8;
27 | public static readonly fp _9 = 9;
28 | public static readonly fp _10 = 10;
29 | public static readonly fp _99 = 99;
30 | public static readonly fp _100 = 100;
31 | public static readonly fp _200 = 200;
32 |
33 | public static readonly fp _0_01 = _1 / _100;
34 | public static readonly fp _0_02 = _0_01 * 2;
35 | public static readonly fp _0_03 = _0_01 * 3;
36 | public static readonly fp _0_04 = _0_01 * 4;
37 | public static readonly fp _0_05 = _0_01 * 5;
38 | public static readonly fp _0_10 = _1 / 10;
39 | public static readonly fp _0_20 = _0_10 * 2;
40 | public static readonly fp _0_25 = _1 / 4;
41 | public static readonly fp _0_33 = _1 / 3;
42 | public static readonly fp _0_50 = _1 / 2;
43 | public static readonly fp _0_75 = _1 - _0_25;
44 | public static readonly fp _0_95 = _1 - _0_05;
45 | public static readonly fp _0_99 = _1 - _0_01;
46 | public static readonly fp _1_01 = _1 + _0_01;
47 | public static readonly fp _1_10 = _1 + _0_10;
48 | public static readonly fp _1_50 = _1 + _0_50;
49 |
50 | public static readonly fp minus_one = -1;
51 | public static readonly fp pi = new fp(205887L);
52 | public static readonly fp pi2 = pi * 2;
53 | public static readonly fp pi_quarter = pi * _0_25;
54 | public static readonly fp pi_half = pi * _0_50;
55 | public static readonly fp one_div_pi2 = 1 / pi2;
56 | public static readonly fp deg2rad = new fp(1143L);
57 | public static readonly fp rad2deg = new fp(3754936L);
58 | public static readonly fp epsilon = new fp(1);
59 | public static readonly fp e = new fp(178145L);
60 |
61 | [FieldOffset(0)]
62 | public long value;
63 |
64 | public long AsLong => value >> fixlut.PRECISION;
65 | public int AsInt => (int) (value >> fixlut.PRECISION);
66 | public float AsFloat => value / 65536f;
67 | public float AsFloatRounded => (float) Math.Round(value / 65536f, 5);
68 | public double AsDouble => value / 65536d;
69 | public double AsDoubleRounded => Math.Round(value / 65536d, 5);
70 |
71 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
72 | internal fp(long v) {
73 | value = v;
74 | }
75 |
76 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
77 | public static fp operator -(fp a) {
78 | a.value = -a.value;
79 | return a;
80 | }
81 |
82 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
83 | public static fp operator +(fp a) {
84 | a.value = +a.value;
85 | return a;
86 | }
87 |
88 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
89 | public static fp operator +(fp a, fp b) {
90 | a.value += b.value;
91 | return a;
92 | }
93 |
94 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
95 | public static fp operator +(fp a, int b) {
96 | a.value += (long) b << fixlut.PRECISION;
97 | return a;
98 | }
99 |
100 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
101 | public static fp operator +(int a, fp b) {
102 | b.value = ((long) a << fixlut.PRECISION) + b.value;
103 | return b;
104 | }
105 |
106 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
107 | public static fp operator -(fp a, fp b) {
108 | a.value -= b.value;
109 | return a;
110 | }
111 |
112 |
113 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
114 | public static fp operator -(fp a, int b) {
115 | a.value -= (long) b << fixlut.PRECISION;
116 | return a;
117 | }
118 |
119 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
120 | public static fp operator -(int a, fp b) {
121 | b.value = ((long) a << fixlut.PRECISION) - b.value;
122 | return b;
123 | }
124 |
125 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
126 | public static fp operator *(fp a, fp b) {
127 | a.value = a.value * b.value >> fixlut.PRECISION;
128 | return a;
129 | }
130 |
131 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
132 | public static fp operator *(fp a, int b) {
133 | a.value *= b;
134 | return a;
135 | }
136 |
137 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
138 | public static fp operator *(int a, fp b) {
139 | b.value *= a;
140 | return b;
141 | }
142 |
143 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
144 | public static fp operator /(fp a, fp b) {
145 | a.value = (a.value << fixlut.PRECISION) / b.value;
146 | return a;
147 | }
148 |
149 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
150 | public static fp operator /(fp a, int b) {
151 | a.value /= b;
152 | return a;
153 | }
154 |
155 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
156 | public static fp operator /(int a, fp b) {
157 | b.value = ((long) a << 32) / b.value;
158 | return b;
159 | }
160 |
161 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
162 | public static fp operator %(fp a, fp b) {
163 | a.value %= b.value;
164 | return a;
165 | }
166 |
167 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
168 | public static fp operator %(fp a, int b) {
169 | a.value %= (long) b << fixlut.PRECISION;
170 | return a;
171 | }
172 |
173 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
174 | public static fp operator %(int a, fp b) {
175 | b.value = ((long) a << fixlut.PRECISION) % b.value;
176 | return b;
177 | }
178 |
179 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
180 | public static bool operator <(fp a, fp b) {
181 | return a.value < b.value;
182 | }
183 |
184 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
185 | public static bool operator <(fp a, int b) {
186 | return a.value < (long) b << fixlut.PRECISION;
187 | }
188 |
189 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
190 | public static bool operator <(int a, fp b) {
191 | return (long) a << fixlut.PRECISION < b.value;
192 | }
193 |
194 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
195 | public static bool operator <=(fp a, fp b) {
196 | return a.value <= b.value;
197 | }
198 |
199 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
200 | public static bool operator <=(fp a, int b) {
201 | return a.value <= (long) b << fixlut.PRECISION;
202 | }
203 |
204 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
205 | public static bool operator <=(int a, fp b) {
206 | return (long) a << fixlut.PRECISION <= b.value;
207 | }
208 |
209 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
210 | public static bool operator >(fp a, fp b) {
211 | return a.value > b.value;
212 | }
213 |
214 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
215 | public static bool operator >(fp a, int b) {
216 | return a.value > (long) b << fixlut.PRECISION;
217 | }
218 |
219 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
220 | public static bool operator >(int a, fp b) {
221 | return (long) a << fixlut.PRECISION > b.value;
222 | }
223 |
224 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
225 | public static bool operator >=(fp a, fp b) {
226 | return a.value >= b.value;
227 | }
228 |
229 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
230 | public static bool operator >=(fp a, int b) {
231 | return a.value >= (long) b << fixlut.PRECISION;
232 | }
233 |
234 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
235 | public static bool operator >=(int a, fp b) {
236 | return (long) a << fixlut.PRECISION >= b.value;
237 | }
238 |
239 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
240 | public static bool operator ==(fp a, fp b) {
241 | return a.value == b.value;
242 | }
243 |
244 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
245 | public static bool operator ==(fp a, int b) {
246 | return a.value == (long) b << fixlut.PRECISION;
247 | }
248 |
249 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
250 | public static bool operator ==(int a, fp b) {
251 | return (long) a << fixlut.PRECISION == b.value;
252 | }
253 |
254 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
255 | public static bool operator !=(fp a, fp b) {
256 | return a.value != b.value;
257 | }
258 |
259 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
260 | public static bool operator !=(fp a, int b) {
261 | return a.value != (long) b << fixlut.PRECISION;
262 | }
263 |
264 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
265 | public static bool operator !=(int a, fp b) {
266 | return (long) a << fixlut.PRECISION != b.value;
267 | }
268 |
269 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
270 | public static implicit operator fp(int value) {
271 | fp f;
272 | f.value = (long) value << fixlut.PRECISION;
273 | return f;
274 | }
275 |
276 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
277 | public static explicit operator int(fp value) {
278 | return (int) (value.value >> fixlut.PRECISION);
279 | }
280 |
281 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
282 | public static explicit operator long(fp value) {
283 | return value.value >> fixlut.PRECISION;
284 | }
285 |
286 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
287 | public static explicit operator float(fp value) {
288 | return value.value / 65536f;
289 | }
290 |
291 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
292 | public static explicit operator double(fp value) {
293 | return value.value / 65536d;
294 | }
295 |
296 | public int CompareTo(fp other) {
297 | return value.CompareTo(other.value);
298 | }
299 |
300 | public bool Equals(fp other) {
301 | return value == other.value;
302 | }
303 |
304 | public override bool Equals(object obj) {
305 | return obj is fp other && this == other;
306 | }
307 |
308 | public override int GetHashCode() {
309 | return value.GetHashCode();
310 | }
311 |
312 | public override string ToString() {
313 | var corrected = Math.Round(AsDouble, 5);
314 | return corrected.ToString("F5", CultureInfo.InvariantCulture);
315 | }
316 |
317 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
318 | public static fp ParseRaw(long value) {
319 | return new fp(value);
320 | }
321 |
322 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
323 | public static fp Parse(long value) {
324 | return new fp(value << fixlut.PRECISION);
325 | }
326 |
327 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
328 | public static fp ParseUnsafe(float value) {
329 | return new fp((long) (value * fixlut.ONE + 0.5f * (value < 0 ? -1 : 1)));
330 | }
331 |
332 | public static fp ParseUnsafe(string value) {
333 | var doubleValue = double.Parse(value, CultureInfo.InvariantCulture);
334 | var longValue = (long) (doubleValue * fixlut.ONE + 0.5d * (doubleValue < 0 ? -1 : 1));
335 | return new fp(longValue);
336 | }
337 |
338 | ///
339 | /// Deterministically parses FP value out of a string
340 | ///
341 | /// Trimmed string to parse
342 | public static fp Parse(string value) {
343 | if (string.IsNullOrEmpty(value))
344 | {
345 | return _0;
346 | }
347 |
348 | bool negative;
349 |
350 | var startIndex = 0;
351 | if (negative = (value[0] == '-')) {
352 | startIndex = 1;
353 | }
354 |
355 | var pointIndex = value.IndexOf('.');
356 | if (pointIndex < startIndex) {
357 | if (startIndex == 0) {
358 | return ParseInteger(value);
359 | }
360 |
361 | return -ParseInteger(value.Substring(startIndex, value.Length - startIndex));
362 |
363 | }
364 |
365 | var result = new fp();
366 |
367 | if (pointIndex > startIndex) {
368 | var integerString = value.Substring(startIndex, pointIndex - startIndex);
369 | result += ParseInteger(integerString);
370 | }
371 |
372 |
373 | if (pointIndex == value.Length - 1) {
374 | return negative ? -result : result;
375 | }
376 |
377 | var fractionString = value.Substring(pointIndex + 1, value.Length - pointIndex - 1);
378 | if (fractionString.Length > 0) {
379 | result += ParseFractions(fractionString);
380 | }
381 |
382 | return negative ? -result : result;
383 | }
384 |
385 | private static fp ParseInteger(string format) {
386 | return Parse(long.Parse(format, CultureInfo.InvariantCulture));
387 | }
388 |
389 | private static fp ParseFractions(string format) {
390 | format = format.Length < 5 ? format.PadRight(5, '0') : format.Substring(0, 5);
391 | return ParseRaw(long.Parse(format, CultureInfo.InvariantCulture) * 65536 / 100000);
392 | }
393 |
394 | public class Comparer : IComparer {
395 | public static readonly Comparer instance = new Comparer();
396 |
397 | private Comparer() { }
398 |
399 | int IComparer.Compare(fp x, fp y) {
400 | return x.value.CompareTo(y.value);
401 | }
402 | }
403 |
404 | public class EqualityComparer : IEqualityComparer {
405 | public static readonly EqualityComparer instance = new EqualityComparer();
406 |
407 | private EqualityComparer() { }
408 |
409 | bool IEqualityComparer.Equals(fp x, fp y) {
410 | return x.value == y.value;
411 | }
412 |
413 | int IEqualityComparer.GetHashCode(fp num) {
414 | return num.value.GetHashCode();
415 | }
416 | }
417 | }
418 | }
--------------------------------------------------------------------------------
/FixedPointSharp/fp2.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Runtime.CompilerServices;
4 | using System.Runtime.InteropServices;
5 |
6 | namespace Deterministic.FixedPoint {
7 | [Serializable]
8 | [StructLayout(LayoutKind.Explicit, Size = SIZE)]
9 | public struct fp2 : IEquatable {
10 | public const int SIZE = 16;
11 |
12 | public static readonly fp2 left = new fp2(-fp._1, fp._0);
13 | public static readonly fp2 right = new fp2(fp._1, fp._0);
14 | public static readonly fp2 up = new fp2(fp._0, fp._1);
15 | public static readonly fp2 down = new fp2(fp._0, -fp._1);
16 | public static readonly fp2 one = new fp2(fp._1, fp._1);
17 | public static readonly fp2 minus_one = new fp2(fp.minus_one, fp.minus_one);
18 | public static readonly fp2 zero = new fp2(fp._0, fp._0);
19 |
20 | [FieldOffset(0)]
21 | public fp x;
22 |
23 | [FieldOffset(8)]
24 | public fp y;
25 |
26 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
27 | public fp2(fp x, fp y) {
28 | this.x.value = x.value;
29 | this.y.value = y.value;
30 | }
31 |
32 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
33 | public static fp2 operator +(fp2 a, fp2 b) {
34 | a.x.value += b.x.value;
35 | a.y.value += b.y.value;
36 | return a;
37 | }
38 |
39 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
40 | public static fp2 operator -(fp2 a, fp2 b) {
41 | a.x.value -= b.x.value;
42 | a.y.value -= b.y.value;
43 |
44 | return a;
45 | }
46 |
47 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
48 | public static fp2 operator -(fp2 a) {
49 | a.x.value = -a.x.value;
50 | a.y.value = -a.y.value;
51 |
52 | return a;
53 | }
54 |
55 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
56 | public static fp2 operator *(fp2 a, fp2 b) {
57 | a.x.value = (a.x.value * b.x.value) >> fixlut.PRECISION;
58 | a.y.value = (a.y.value * b.y.value) >> fixlut.PRECISION;
59 |
60 | return a;
61 | }
62 |
63 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
64 | public static fp2 operator *(fp2 a, fp b) {
65 | a.x.value = (a.x.value * b.value) >> fixlut.PRECISION;
66 | a.y.value = (a.y.value * b.value) >> fixlut.PRECISION;
67 |
68 | return a;
69 | }
70 |
71 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
72 | public static fp2 operator *(fp b, fp2 a) {
73 | a.x.value = (a.x.value * b.value) >> fixlut.PRECISION;
74 | a.y.value = (a.y.value * b.value) >> fixlut.PRECISION;
75 |
76 | return a;
77 | }
78 |
79 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
80 | public static fp2 operator /(fp2 a, fp2 b) {
81 | a.x.value = (a.x.value << fixlut.PRECISION) / b.x.value;
82 | a.y.value = (a.y.value << fixlut.PRECISION) / b.y.value;
83 |
84 | return a;
85 | }
86 |
87 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
88 | public static fp2 operator /(fp2 a, fp b) {
89 | a.x.value = (a.x.value << fixlut.PRECISION) / b.value;
90 | a.y.value = (a.y.value << fixlut.PRECISION) / b.value;
91 |
92 | return a;
93 | }
94 |
95 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
96 | public static fp2 operator /(fp b, fp2 a) {
97 | a.x.value = (a.x.value << fixlut.PRECISION) / b.value;
98 | a.y.value = (a.y.value << fixlut.PRECISION) / b.value;
99 |
100 | return a;
101 | }
102 |
103 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
104 | public static bool operator ==(fp2 a, fp2 b) {
105 | return a.x.value == b.x.value && a.y.value == b.y.value;
106 | }
107 |
108 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
109 | public static bool operator !=(fp2 a, fp2 b) {
110 | return a.x.value != b.x.value || a.y.value != b.y.value;
111 | }
112 |
113 | public override bool Equals(object obj) {
114 | return obj is fp2 other && this == other;
115 | }
116 |
117 | public bool Equals(fp2 other) {
118 | return this == other;
119 | }
120 |
121 | public override int GetHashCode() {
122 | unchecked {
123 | return (x.GetHashCode() * 397) ^ y.GetHashCode();
124 | }
125 | }
126 |
127 | public override string ToString() {
128 | return $"({x}, {y})";
129 | }
130 |
131 | public class EqualityComparer : IEqualityComparer {
132 | public static readonly EqualityComparer instance = new EqualityComparer();
133 |
134 | private EqualityComparer() { }
135 |
136 | bool IEqualityComparer.Equals(fp2 x, fp2 y) {
137 | return x == y;
138 | }
139 |
140 | int IEqualityComparer.GetHashCode(fp2 obj) {
141 | return obj.GetHashCode();
142 | }
143 | }
144 |
145 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
146 | public fp2 Normalize() {
147 | return fixmath.Normalize(this);
148 | }
149 |
150 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
151 | public fp Magnitude() {
152 | return fixmath.Magnitude(this);
153 | }
154 |
155 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
156 | public fp MagnitudeSqr() {
157 | return fixmath.MagnitudeSqr(this);
158 | }
159 | }
160 | }
--------------------------------------------------------------------------------
/FixedPointSharp/fp3.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Runtime.CompilerServices;
4 | using System.Runtime.InteropServices;
5 |
6 | namespace Deterministic.FixedPoint {
7 | [Serializable]
8 | [StructLayout(LayoutKind.Explicit, Size = SIZE)]
9 | public struct fp3 : IEquatable {
10 | public const int SIZE = 24;
11 |
12 | public static readonly fp3 left = new fp3(-fp._1, fp._0, fp._0);
13 | public static readonly fp3 right = new fp3(fp._1, fp._0, fp._0);
14 | public static readonly fp3 up = new fp3(fp._0, fp._1, fp._0);
15 | public static readonly fp3 down = new fp3(fp._0, fp.minus_one, fp._0);
16 | public static readonly fp3 forward = new fp3(fp._0, fp._0, fp._1);
17 | public static readonly fp3 backward = new fp3(fp._0, fp._0, fp.minus_one);
18 | public static readonly fp3 one = new fp3(fp._1, fp._1, fp._1);
19 | public static readonly fp3 minus_one = new fp3(fp.minus_one, fp.minus_one, fp.minus_one);
20 | public static readonly fp3 zero = new fp3(fp._0, fp._0, fp._0);
21 |
22 | [FieldOffset(0)]
23 | public fp x;
24 |
25 | [FieldOffset(8)]
26 | public fp y;
27 |
28 | [FieldOffset(16)]
29 | public fp z;
30 |
31 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
32 | public fp3(fp x, fp y, fp z) {
33 | this.x.value = x.value;
34 | this.y.value = y.value;
35 | this.z.value = z.value;
36 | }
37 |
38 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
39 | public fp3(fp2 xy, fp z) {
40 | x.value = xy.x.value;
41 | y.value = xy.y.value;
42 | this.z.value = z.value;
43 | }
44 |
45 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
46 | public static fp3 operator +(fp3 a, fp3 b) {
47 | a.x.value += b.x.value;
48 | a.y.value += b.y.value;
49 | a.z.value += b.z.value;
50 |
51 | return a;
52 | }
53 |
54 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
55 | public static fp3 operator -(fp3 a, fp3 b) {
56 | a.x.value -= b.x.value;
57 | a.y.value -= b.y.value;
58 | a.z.value -= b.z.value;
59 |
60 | return a;
61 | }
62 |
63 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
64 | public static fp3 operator -(fp3 a) {
65 | a.x.value = -a.x.value;
66 | a.y.value = -a.y.value;
67 | a.z.value = -a.z.value;
68 |
69 | return a;
70 | }
71 |
72 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
73 | public static fp3 operator *(fp3 a, fp3 b) {
74 | a.x.value = (a.x.value * b.x.value) >> fixlut.PRECISION;
75 | a.y.value = (a.y.value * b.y.value) >> fixlut.PRECISION;
76 | a.z.value = (a.z.value * b.z.value) >> fixlut.PRECISION;
77 |
78 | return a;
79 | }
80 |
81 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
82 | public static fp3 operator *(fp3 a, fp b) {
83 | a.x.value = (a.x.value * b.value) >> fixlut.PRECISION;
84 | a.y.value = (a.y.value * b.value) >> fixlut.PRECISION;
85 | a.z.value = (a.z.value * b.value) >> fixlut.PRECISION;
86 |
87 | return a;
88 | }
89 |
90 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
91 | public static fp3 operator *(fp b, fp3 a) {
92 | a.x.value = (a.x.value * b.value) >> fixlut.PRECISION;
93 | a.y.value = (a.y.value * b.value) >> fixlut.PRECISION;
94 | a.z.value = (a.z.value * b.value) >> fixlut.PRECISION;
95 |
96 | return a;
97 | }
98 |
99 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
100 | public static fp3 operator /(fp3 a, fp3 b) {
101 | a.x.value = (a.x.value << fixlut.PRECISION) / b.x.value;
102 | a.y.value = (a.y.value << fixlut.PRECISION) / b.y.value;
103 | a.z.value = (a.z.value << fixlut.PRECISION) / b.z.value;
104 |
105 | return a;
106 | }
107 |
108 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
109 | public static fp3 operator /(fp3 a, fp b) {
110 | a.x.value = (a.x.value << fixlut.PRECISION) / b.value;
111 | a.y.value = (a.y.value << fixlut.PRECISION) / b.value;
112 | a.z.value = (a.z.value << fixlut.PRECISION) / b.value;
113 |
114 | return a;
115 | }
116 |
117 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
118 | public static fp3 operator /(fp b, fp3 a) {
119 | a.x.value = (a.x.value << fixlut.PRECISION) / b.value;
120 | a.y.value = (a.y.value << fixlut.PRECISION) / b.value;
121 | a.z.value = (a.z.value << fixlut.PRECISION) / b.value;
122 |
123 | return a;
124 | }
125 |
126 |
127 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
128 | public static bool operator ==(fp3 a, fp3 b) {
129 | return a.x.value == b.x.value && a.y.value == b.y.value && a.z.value == b.z.value;
130 | }
131 |
132 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
133 | public static bool operator !=(fp3 a, fp3 b) {
134 | return a.x.value != b.x.value || a.y.value != b.y.value || a.z.value != b.z.value;
135 | }
136 |
137 | public bool Equals(fp3 other) {
138 | return x.Equals(other.x) && y.Equals(other.y) && z.Equals(other.z);
139 | }
140 |
141 | public override bool Equals(object obj) {
142 | return obj is fp3 other && this == other;
143 | }
144 |
145 | public override int GetHashCode() {
146 | unchecked {
147 | var hashCode = x.GetHashCode();
148 | hashCode = (hashCode * 397) ^ y.GetHashCode();
149 | hashCode = (hashCode * 397) ^ z.GetHashCode();
150 | return hashCode;
151 | }
152 | }
153 |
154 | public override string ToString() {
155 | return $"({x}, {y}, {z})";
156 | }
157 |
158 | public class EqualityComparer : IEqualityComparer {
159 | public static readonly EqualityComparer instance = new EqualityComparer();
160 |
161 | private EqualityComparer() { }
162 |
163 | bool IEqualityComparer.Equals(fp3 x, fp3 y) {
164 | return x == y;
165 | }
166 |
167 | int IEqualityComparer.GetHashCode(fp3 obj) {
168 | return obj.GetHashCode();
169 | }
170 | }
171 |
172 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
173 | public fp3 Normalize() {
174 | return fixmath.Normalize(this);
175 | }
176 | }
177 | }
--------------------------------------------------------------------------------
/FixedPointSharp/fp4.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | namespace Deterministic.FixedPoint {
6 | [StructLayout(LayoutKind.Explicit, Size = SIZE)]
7 | public struct fp4 : IEquatable {
8 | public const int SIZE = 32;
9 |
10 | [FieldOffset(0)]
11 | public fp x;
12 |
13 | [FieldOffset(8)]
14 | public fp y;
15 |
16 | [FieldOffset(16)]
17 | public fp z;
18 |
19 | [FieldOffset(24)]
20 | public fp w;
21 |
22 | public static readonly fp4 zero;
23 | public static readonly fp4 one = new fp4 {x = fp._1, y = fp._1, z = fp._1, w = fp._1};
24 | public static readonly fp4 minus_one = new fp4 {x = fp.minus_one, y = fp.minus_one, z = fp.minus_one, w = fp.minus_one};
25 |
26 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
27 | public fp4(fp x, fp y, fp z, fp w) {
28 | this.x = x;
29 | this.y = y;
30 | this.z = z;
31 | this.w = w;
32 | }
33 |
34 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
35 | public fp4(fp2 xy, fp2 zw) {
36 | x = xy.x;
37 | y = xy.y;
38 | z = zw.x;
39 | w = zw.y;
40 | }
41 |
42 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
43 | public fp4(fp3 v, fp w) {
44 | x = v.x;
45 | y = v.y;
46 | z = v.z;
47 | this.w = w;
48 | }
49 |
50 | ///
51 | /// Initializes fp4 vector with 48.16 fp format long values
52 | ///
53 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
54 | internal fp4(long x, long y, long z, long w) {
55 | this.x.value = x;
56 | this.y.value = y;
57 | this.z.value = z;
58 | this.w.value = w;
59 | }
60 |
61 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
62 | public static fp4 operator *(fp4 lhs, fp4 rhs) {
63 | return new fp4((lhs.x.value * rhs.x.value) >> fixlut.PRECISION, (lhs.y.value * rhs.y.value) >> fixlut.PRECISION,
64 | (lhs.z.value * rhs.z.value) >> fixlut.PRECISION, (lhs.w.value * rhs.w.value) >> fixlut.PRECISION);
65 | }
66 |
67 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
68 | public static fp4 operator *(fp4 lhs, fp rhs) {
69 | return new fp4(lhs.x * rhs, lhs.y * rhs, lhs.z * rhs, lhs.w * rhs);
70 | }
71 |
72 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
73 | public static fp4 operator *(fp lhs, fp4 rhs) {
74 | return new fp4(lhs * rhs.x, lhs * rhs.y, lhs * rhs.z, lhs * rhs.w);
75 | }
76 |
77 |
78 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
79 | public static fp4 operator +(fp4 lhs, fp4 rhs) {
80 | return new fp4(lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z, lhs.w + rhs.w);
81 | }
82 |
83 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
84 | public static fp4 operator +(fp4 lhs, fp rhs) {
85 | return new fp4(lhs.x + rhs, lhs.y + rhs, lhs.z + rhs, lhs.w + rhs);
86 | }
87 |
88 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
89 | public static fp4 operator +(fp lhs, fp4 rhs) {
90 | return new fp4(lhs + rhs.x, lhs + rhs.y, lhs + rhs.z, lhs + rhs.w);
91 | }
92 |
93 |
94 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
95 | public static fp4 operator -(fp4 lhs, fp4 rhs) {
96 | return new fp4(lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z, lhs.w - rhs.w);
97 | }
98 |
99 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
100 | public static fp4 operator -(fp4 lhs, fp rhs) {
101 | return new fp4(lhs.x - rhs, lhs.y - rhs, lhs.z - rhs, lhs.w - rhs);
102 | }
103 |
104 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
105 | public static fp4 operator -(fp lhs, fp4 rhs) {
106 | return new fp4(lhs - rhs.x, lhs - rhs.y, lhs - rhs.z, lhs - rhs.w);
107 | }
108 |
109 |
110 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
111 | public static fp4 operator /(fp4 lhs, fp4 rhs) {
112 | return new fp4(lhs.x / rhs.x, lhs.y / rhs.y, lhs.z / rhs.z, lhs.w / rhs.w);
113 | }
114 |
115 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
116 | public static fp4 operator /(fp4 lhs, fp rhs) {
117 | return new fp4(lhs.x / rhs, lhs.y / rhs, lhs.z / rhs, lhs.w / rhs);
118 | }
119 |
120 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
121 | public static fp4 operator /(fp lhs, fp4 rhs) {
122 | return new fp4(lhs / rhs.x, lhs / rhs.y, lhs / rhs.z, lhs / rhs.w);
123 | }
124 |
125 |
126 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
127 | public static fp4 operator %(fp4 lhs, fp4 rhs) {
128 | return new fp4(lhs.x % rhs.x, lhs.y % rhs.y, lhs.z % rhs.z, lhs.w % rhs.w);
129 | }
130 |
131 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
132 | public static fp4 operator %(fp4 lhs, fp rhs) {
133 | return new fp4(lhs.x % rhs, lhs.y % rhs, lhs.z % rhs, lhs.w % rhs);
134 | }
135 |
136 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
137 | public static fp4 operator %(fp lhs, fp4 rhs) {
138 | return new fp4(lhs % rhs.x, lhs % rhs.y, lhs % rhs.z, lhs % rhs.w);
139 | }
140 |
141 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
142 | public static bool operator ==(fp4 a, fp4 b) {
143 | return a.x.value == b.x.value && a.y.value == b.y.value && a.z.value == b.z.value && a.w.value == b.w.value;
144 | }
145 |
146 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
147 | public static bool operator !=(fp4 a, fp4 b) {
148 | return a.x.value != b.x.value || a.y.value != b.y.value || a.z.value != b.z.value || a.w.value != b.w.value;
149 | }
150 |
151 | public bool Equals(fp4 other) {
152 | return x.Equals(other.x) && y.Equals(other.y) && z.Equals(other.z) && w.Equals(other.w);
153 | }
154 |
155 | public override bool Equals(object obj) {
156 | return obj is fp4 other && Equals(other);
157 | }
158 |
159 | public override int GetHashCode() {
160 | unchecked {
161 | var hashCode = x.GetHashCode();
162 | hashCode = (hashCode * 397) ^ y.GetHashCode();
163 | hashCode = (hashCode * 397) ^ z.GetHashCode();
164 | hashCode = (hashCode * 397) ^ w.GetHashCode();
165 | return hashCode;
166 | }
167 | }
168 | }
169 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Roman Zhuravlev
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/LUTGenerator/Data.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | namespace LUTGenerator {
5 | public static class Data {
6 | public const int PRECISION = 16;
7 | public const long ONE = 1 << PRECISION;
8 |
9 | public const int SIN_VALUE_COUNT = 512;
10 | public const int SIN_COS_VALUE_COUNT = 512;
11 | public const int TAN_VALUE_COUNT = 512;
12 | public const int ACOS_VALUE_COUNT = 512;
13 | public const int ASIN_VALUE_COUNT = 512;
14 |
15 | public static readonly List SinLut = new List(SIN_VALUE_COUNT + 1);
16 | public static readonly List SinCosLut = new List(SIN_COS_VALUE_COUNT * 2 + 2);
17 | public static readonly List TanLut = new List(TAN_VALUE_COUNT + 1);
18 | public static readonly List AcosLut = new List(ACOS_VALUE_COUNT + 2);
19 | public static readonly List AsinLut = new List(ASIN_VALUE_COUNT + 2);
20 |
21 | static Data() {
22 | for (var i = 0; i < SIN_COS_VALUE_COUNT; i++) {
23 | var angle = 2 * Math.PI * i / SIN_COS_VALUE_COUNT;
24 |
25 | var sinValue = Math.Sin(angle);
26 | var movedSin = sinValue * ONE;
27 | var roundedSin = movedSin > 0 ? movedSin + 0.5f : movedSin - 0.5f;
28 | SinLut.Add((int) roundedSin);
29 | }
30 |
31 | SinLut.Add(SinLut[0]);
32 |
33 | for (var i = 0; i < SIN_COS_VALUE_COUNT; i++) {
34 | var angle = 2 * Math.PI * i / SIN_COS_VALUE_COUNT;
35 |
36 | var sinValue = Math.Sin(angle);
37 | var movedSin = sinValue * ONE;
38 | var roundedSin = movedSin > 0 ? movedSin + 0.5f : movedSin - 0.5f;
39 | SinCosLut.Add((int) roundedSin);
40 |
41 | var cosValue = Math.Cos(angle);
42 | var movedCos = cosValue * ONE;
43 | var roundedCos = movedCos > 0 ? movedCos + 0.5f : movedCos - 0.5f;
44 | SinCosLut.Add((int) roundedCos);
45 | }
46 |
47 | SinCosLut.Add(SinCosLut[0]);
48 | SinCosLut.Add(SinCosLut[1]);
49 |
50 | for (var i = 0; i < TAN_VALUE_COUNT; i++) {
51 | var angle = 2 * Math.PI * i / TAN_VALUE_COUNT;
52 |
53 | var value = Math.Tan(angle);
54 | var moved = value * ONE;
55 | var rounded = moved > 0 ? moved + 0.5f : moved - 0.5f;
56 | TanLut.Add((int) rounded);
57 | }
58 |
59 | TanLut.Add(TanLut[0]);
60 |
61 | for (var i = 0; i < ASIN_VALUE_COUNT; i++) {
62 | var angle = 2f * i / ASIN_VALUE_COUNT;
63 | angle -= 1;
64 |
65 | if (i == ASIN_VALUE_COUNT - 1)
66 | angle = 1;
67 |
68 | var value = Math.Asin(angle);
69 | var moved = value * ONE;
70 | var rounded = moved > 0 ? moved + 0.5f : moved - 0.5f;
71 | AsinLut.Add((int) rounded);
72 | }
73 |
74 | //Special handling for value of 1, as graph is not symmetric
75 | AsinLut.Add(AsinLut[ASIN_VALUE_COUNT - 1]);
76 | AsinLut.Add(AsinLut[ASIN_VALUE_COUNT - 1]);
77 |
78 | for (var i = 0; i < ACOS_VALUE_COUNT; i++) {
79 | var angle = 2f * i / ACOS_VALUE_COUNT;
80 | angle -= 1;
81 |
82 | if (i == ACOS_VALUE_COUNT - 1)
83 | angle = 1;
84 |
85 | var value = Math.Acos(angle);
86 | var moved = value * ONE;
87 | var rounded = moved > 0 ? moved + 0.5f : moved - 0.5f;
88 | AcosLut.Add((int) rounded);
89 | }
90 |
91 | //Special handling for value of 1, as graph is not symmetric
92 | AcosLut.Add(AcosLut[ACOS_VALUE_COUNT - 1]);
93 | AcosLut.Add(AcosLut[ACOS_VALUE_COUNT - 1]);
94 | }
95 | }
96 | }
--------------------------------------------------------------------------------
/LUTGenerator/Generator.cs:
--------------------------------------------------------------------------------
1 | namespace LUTGenerator {
2 | internal class Generator {
3 | public static void Main(string[] args) {
4 | Writer.Write(Data.SinLut, "SinLut", "Sin");
5 | Writer.Write(Data.SinCosLut, "SinCosLut", "Sin");
6 | Writer.Write(Data.TanLut, "TanLut", "Sin");
7 | Writer.Write(Data.AcosLut, "AcosLut", "Sin");
8 | Writer.Write(Data.AsinLut, "AsinLut", "Sin");
9 | }
10 | }
11 | }
--------------------------------------------------------------------------------
/LUTGenerator/LUTGenerator.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {49D328B2-A15B-42A7-9C16-B04E160FE7B3}
8 | Exe
9 | Properties
10 | LUTGenerator
11 | LUTGenerator
12 | v4.7.1
13 | 512
14 |
15 |
16 | AnyCPU
17 | true
18 | full
19 | false
20 | bin\Debug\
21 | DEBUG;TRACE
22 | prompt
23 | 4
24 |
25 |
26 | AnyCPU
27 | pdbonly
28 | true
29 | bin\Release\
30 | TRACE
31 | prompt
32 | 4
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
54 |
--------------------------------------------------------------------------------
/LUTGenerator/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.InteropServices;
3 |
4 | // General Information about an assembly is controlled through the following
5 | // set of attributes. Change these attribute values to modify the information
6 | // associated with an assembly.
7 | [assembly: AssemblyTitle("LUTGenerator")]
8 | [assembly: AssemblyDescription("")]
9 | [assembly: AssemblyConfiguration("")]
10 | [assembly: AssemblyCompany("")]
11 | [assembly: AssemblyProduct("LUTGenerator")]
12 | [assembly: AssemblyCopyright("Copyright © 2020")]
13 | [assembly: AssemblyTrademark("")]
14 | [assembly: AssemblyCulture("")]
15 |
16 | // Setting ComVisible to false makes the types in this assembly not visible
17 | // to COM components. If you need to access a type in this assembly from
18 | // COM, set the ComVisible attribute to true on that type.
19 | [assembly: ComVisible(false)]
20 |
21 | // The following GUID is for the ID of the typelib if this project is exposed to COM
22 | [assembly: Guid("49D328B2-A15B-42A7-9C16-B04E160FE7B3")]
23 |
24 | // Version information for an assembly consists of the following four values:
25 | //
26 | // Major Version
27 | // Minor Version
28 | // Build Number
29 | // Revision
30 | //
31 | // You can specify all the values or you can default the Build and Revision Numbers
32 | // by using the '*' as shown below:
33 | // [assembly: AssemblyVersion("1.0.*")]
34 | [assembly: AssemblyVersion("1.0.0.0")]
35 | [assembly: AssemblyFileVersion("1.0.0.0")]
--------------------------------------------------------------------------------
/LUTGenerator/Writer.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 | using System.Collections.Generic;
4 | using System.IO;
5 |
6 | namespace LUTGenerator {
7 | public static class Writer {
8 | public const string HEADER = "namespace FixedPoint {\n public static partial class fixlut {\n public static readonly";
9 | public const string FOOTER = "\n };\n }\n}";
10 | public const int ENTRIES_PER_LINE = 10;
11 |
12 | public static string Output = string.Empty;
13 | public static int EntryIndex = 0;
14 | public static int MaxEntryIndex;
15 |
16 | private static readonly Dictionary _friendlyNames = new Dictionary {
17 | {typeof(int), "int"},
18 | {typeof(uint), "uint"},
19 | {typeof(long), "long"},
20 | {typeof(ulong), "ulong"},
21 | {typeof(short), "short"},
22 | {typeof(ushort), "ushort"},
23 | {typeof(byte), "byte"},
24 | {typeof(sbyte), "sbyte"},
25 | };
26 |
27 | public static void Write(IList list, string fieldName, string fileName) {
28 | EntryIndex = 0;
29 | MaxEntryIndex = list.Count - 1;
30 | Output = $"{HEADER} {_friendlyNames[list[0].GetType()]}[] {fieldName} = {{";
31 |
32 | foreach (var i in list) {
33 | AddEntry(i.ToString());
34 | }
35 |
36 | Output += FOOTER;
37 |
38 | File.WriteAllText($"{Directory.GetCurrentDirectory()}/{fieldName}.cs", Output);
39 | }
40 |
41 | public static void AddEntry(string entry) {
42 | if (EntryIndex % ENTRIES_PER_LINE == 0)
43 | Output += "\n ";
44 | else
45 | Output += " ";
46 |
47 | Output += entry;
48 |
49 | if (EntryIndex != MaxEntryIndex)
50 | Output += ",";
51 |
52 | EntryIndex++;
53 | }
54 | }
55 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # FixedPoint-Sharp
2 |
3 | ## Features
4 | - LUT-based trigonometry with lerping
5 | - 48.16 precision
6 | - 2D, 3D, 4D vector types
7 | - 1D, 2D, 3D, 4D math
8 | - Random generator for fp, int, bool, and vector types
9 | - A huge pile of tests
10 |
--------------------------------------------------------------------------------
/UnitTests/FP_Tests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Globalization;
3 | using Deterministic.FixedPoint;
4 | using FluentAssertions;
5 | using NUnit.Framework;
6 |
7 | namespace UnitTests
8 | {
9 | public class FP_Tests {
10 | private const string PRECISION_FORMAT = "F4";
11 | private const int ROUNDING = 5;
12 |
13 | [Test]
14 | public void ToStringTest()
15 | {
16 | var originalFp = fp._1 - fp._0_01;
17 | Math.Round(originalFp.AsDouble, ROUNDING).ToString(PRECISION_FORMAT, CultureInfo.InvariantCulture).Should().Be("0.9900");
18 |
19 | originalFp = fp._1 - fp._0_01 *fp._0_01;
20 | Math.Round(originalFp.AsDouble, ROUNDING).ToString(PRECISION_FORMAT, CultureInfo.InvariantCulture).Should().Be("0.9999");
21 |
22 | originalFp = fp._1;
23 | Math.Round(originalFp.AsDouble, ROUNDING).ToString(PRECISION_FORMAT, CultureInfo.InvariantCulture).Should().Be("1.0000");
24 |
25 | originalFp = fp._1 + fp._0_01;
26 | Math.Round(originalFp.AsDouble, ROUNDING).ToString(PRECISION_FORMAT, CultureInfo.InvariantCulture).Should().Be("1.0100");
27 |
28 | originalFp = fp._1 + fp._0_01 * fp._0_01;
29 | Math.Round(originalFp.AsDouble, ROUNDING).ToString(PRECISION_FORMAT, CultureInfo.InvariantCulture).Should().Be("1.0001");
30 |
31 | originalFp = fp._0_01;
32 | Math.Round(originalFp.AsDouble, ROUNDING).ToString(PRECISION_FORMAT, CultureInfo.InvariantCulture).Should().Be("0.0100");
33 |
34 | originalFp = fp._0_50;
35 | Math.Round(originalFp.AsDouble, ROUNDING).ToString(PRECISION_FORMAT, CultureInfo.InvariantCulture).Should().Be("0.5000");
36 | }
37 |
38 | [Test]
39 | public void SlowStringParsingTest() {
40 | fp.Parse("5").AsFloatRounded.Should().BeApproximately(5, 0.0001f);
41 | fp.Parse("5.").AsFloatRounded.Should().BeApproximately(5, 0.0001f);
42 | fp.Parse(".1").AsFloatRounded.Should().BeApproximately(0.1f, 0.0001f);
43 | fp.Parse("5.1").AsFloatRounded.Should().BeApproximately(5.1f, 0.0001f);
44 | fp.Parse("5.45111111").AsFloatRounded.Should().BeApproximately(5.4511f, 0.0001f);
45 |
46 | fp.Parse("-5").AsFloatRounded.Should().BeApproximately(-5, 0.0001f);
47 | fp.Parse("-5.").AsFloatRounded.Should().BeApproximately(-5, 0.0001f);
48 | fp.Parse("-.1").AsFloatRounded.Should().BeApproximately(-0.1f, 0.0001f);
49 | fp.Parse("-5.1").AsFloatRounded.Should().BeApproximately(-5.1f, 0.0001f);
50 | }
51 |
52 | [Test]
53 | public void SlowFromToStringTest() {
54 | var from = -100.0;
55 | var to = 100.0;
56 | var delta = 0.0001;
57 |
58 | for (var v = from; v < to; v += delta) {
59 | var parsedString = Math.Round(v, ROUNDING).ToString(PRECISION_FORMAT, CultureInfo.InvariantCulture);
60 | var parsedFp = fp.Parse(parsedString);
61 | var convertedBackFloat = parsedFp.AsDouble;
62 | convertedBackFloat.Should().BeApproximately(v, 0.0001);
63 | }
64 | }
65 |
66 | [Test]
67 | public void FromToStringTest() {
68 | var from = -100.0;
69 | var to = 100.0;
70 | var delta = 0.0001;
71 |
72 | for (var v = from; v < to; v += delta) {
73 | var parsedString = Math.Round(v, ROUNDING).ToString(PRECISION_FORMAT, CultureInfo.InvariantCulture);
74 | var parsedFp = fp.ParseUnsafe(parsedString);
75 | var convertedBackFloat = parsedFp.AsDouble;
76 | convertedBackFloat.Should().BeApproximately(v, 0.0001);
77 | }
78 | }
79 |
80 | [Test]
81 | public void FromFloatTest() {
82 | var from = -100.0;
83 | var to = 100.0;
84 | var delta = 0.0001;
85 |
86 | for (var v = from; v < to; v += delta) {
87 | var parsedFp = fp.ParseUnsafe((float)v);
88 | var convertedBackFloat = parsedFp.AsDouble;
89 | convertedBackFloat.Should().BeApproximately(v, 0.0001);
90 | }
91 | }
92 |
93 | [Test]
94 | public void AsIntTest() {
95 | var from = -65000f;
96 | var to = 65000;
97 | var delta = 0.1f;
98 |
99 | for (float v = from; v < to; v += delta) {
100 | var originalInt = (int) Math.Floor(v);
101 | var parsedFp = fp.ParseUnsafe(v);
102 | var convertedBack = parsedFp.AsInt;
103 | convertedBack.Should().Be(originalInt);
104 | }
105 | }
106 | }
107 | }
--------------------------------------------------------------------------------
/UnitTests/FP_fixmath3Tests.cs:
--------------------------------------------------------------------------------
1 | using Deterministic.FixedPoint;
2 | using FluentAssertions;
3 | using NUnit.Framework;
4 |
5 | namespace UnitTests
6 | {
7 | public class FP_fixmath3Tests
8 | {
9 | [Test]
10 | public void NormalizationTest()
11 | {
12 | var originalVector = new fp3(fp._5, fp._0, fp._0);
13 | var modifiedVector = fixmath.Normalize(originalVector);
14 |
15 | modifiedVector.Should().Be(new fp3(fp._1, fp._0, fp._0));
16 | }
17 |
18 | [Test]
19 | public void MagnitudeTest()
20 | {
21 | var originalVector = new fp3(fp._5, fp._0, fp._0);
22 | var magnitude = fixmath.Magnitude(originalVector);
23 |
24 | magnitude.Should().Be(fp._5);
25 | }
26 |
27 | [Test]
28 | public void MagnitudeSqrTest()
29 | {
30 | var originalVector = new fp3(fp._5, fp._0, fp._0);
31 | var magnitude = fixmath.MagnitudeSqr(originalVector);
32 |
33 | magnitude.Should().Be(fp._5 * fp._5);
34 | }
35 |
36 | [Test]
37 | public void MagnitudeClampTest()
38 | {
39 | var originalVector = new fp3(fp._5, fp._0, fp._0);
40 | var clampedVector = fixmath.MagnitudeClamp(originalVector, fp._1_10);
41 |
42 | clampedVector.x.AsFloat.Should().BeApproximately(1.10f, 0.01f);
43 | clampedVector.y.AsFloat.Should().Be(0f);
44 | clampedVector.z.AsFloat.Should().Be(0f);
45 | }
46 |
47 | [Test]
48 | public void DotTest()
49 | {
50 | var vector1 = new fp3(fp._5, fp._0, fp._0);
51 | var vector2 = new fp3(fp._5, fp._0, fp._0);
52 | var dot = fixmath.Dot(vector1, vector2);
53 |
54 | dot.Should().Be(fp._5 * fp._5);
55 |
56 | vector1 = new fp3(fp._1, fp._5, fp._4);
57 | vector2 = new fp3(fp._2, fp._0, fp._1);
58 | dot = fixmath.Dot(vector1, vector2);
59 |
60 | dot.Should().Be(fp._6);
61 |
62 | vector1 = new fp3(fp._0_10, fp._0_75, fp._0_10);
63 | vector2 = new fp3(fp._0_50+fp._0_10, fp._0_20, fp._0_33);
64 | dot = fixmath.Dot(vector1, vector2);
65 |
66 | var str = $"{vector1.x.AsFloat},{vector1.y.value},{vector1.z.value} | {vector2} {dot}";
67 |
68 | dot.AsFloat.Should().BeApproximately(0.243f, 0.01f);
69 | }
70 |
71 | [Test]
72 | public void AngleTest()
73 | {
74 | var vector1 = new fp3(fp._1, fp._5, fp._4);
75 | var vector2 = new fp3(fp._2, fp._0, fp._1);
76 | var angle = fixmath.Angle(vector1, vector2);
77 |
78 | angle.AsInt.Should().Be(65);
79 |
80 | vector1 = new fp3(fp._2, fp._1, fp._1);
81 | vector2 = new fp3(fp._2, fp._0, fp._1);
82 | angle = fixmath.Angle(vector1, vector2);
83 |
84 | angle.AsInt.Should().Be(24);
85 | }
86 |
87 | [Test]
88 | public void AngleSignedTest()
89 | {
90 | var vector1 = new fp3(fp._1, fp._5, fp._4);
91 | var vector2 = new fp3(fp._2, fp._0, fp._1);
92 | var angle = fixmath.AngleSigned(vector1, vector2, fp3.up);
93 |
94 | angle.AsInt.Should().Be(65);
95 |
96 | vector1 = new fp3(-fp._2, fp._1, fp._1);
97 | vector2 = new fp3(fp._2, fp._1, fp._1);
98 | angle = fixmath.AngleSigned(vector1, vector2, fp3.up);
99 |
100 | angle.AsFloat.Should().BeApproximately(109.47f, 0.1f);
101 | }
102 |
103 | [Test]
104 | public void RadiansTest()
105 | {
106 | var vector1 = new fp3(fp._1, fp._5, fp._4);
107 | var vector2 = new fp3(fp._2, fp._0, fp._1);
108 | var angle = fixmath.Radians(vector1, vector2);
109 |
110 | angle.AsInt.Should().Be(1);
111 |
112 | vector1 = new fp3(fp._2, fp._1, fp._1);
113 | vector2 = new fp3(fp._2, fp._0, fp._1);
114 | angle = fixmath.Radians(vector1, vector2);
115 |
116 | angle.AsFloat.Should().BeApproximately(0.42f, 0.01f);
117 | }
118 |
119 | [Test]
120 | public void CrossTest()
121 | {
122 | var vector1 = new fp3(fp._1, fp._5, fp._4);
123 | var vector2 = new fp3(fp._2, fp._0, fp._1);
124 | var cross = fixmath.Cross(vector1, vector2);
125 |
126 | cross.Should().Be(new fp3(fp._5, fp._7, -fp._10));
127 | }
128 |
129 | [Test]
130 | public void ReflectTest()
131 | {
132 | var vector = new fp3(fp._5, fp._0, fp._5);
133 | var normal = new fp3(-fp._1, fp._0, fp._0);
134 | var reflection = fixmath.Reflect(vector, normal);
135 |
136 | reflection.Should().Be(new fp3(-fp._5, fp._0, fp._5));
137 | }
138 |
139 | [Test]
140 | public void ProjectTest()
141 | {
142 | var vector = new fp3(fp._5, fp._0, fp._5);
143 | var normal = new fp3(-fp._1, fp._0, fp._0);
144 | var projection = fixmath.Project(vector, normal);
145 |
146 | projection.Should().Be(new fp3(fp._5, fp._0, fp._0));
147 | }
148 |
149 | [Test]
150 | public void ProjectOnPlaneTest()
151 | {
152 | var vector = new fp3(fp._5, fp._1, fp._5);
153 | var normal = new fp3(-fp._1, fp._0, fp._0);
154 | var projection = fixmath.ProjectOnPlane(vector, normal);
155 |
156 | projection.Should().Be(new fp3(fp._0, fp._1, fp._5));
157 | }
158 |
159 | [Test]
160 | public void LerpTest()
161 | {
162 | var @from = new fp3(fp._5, fp._0, fp._5);
163 | var to = new fp3(fp._0, fp._0, fp._0);
164 | var lerped = fixmath.Lerp(@from, to, fp._0_50);
165 |
166 | lerped.Should().Be(new fp3(fp._2+fp._0_50, fp._0, fp._2 +fp._0_50));
167 | }
168 |
169 | [Test]
170 | public void MoveTowardsTest()
171 | {
172 | var current = fp3.one;
173 | var target = new fp3(fp._5, fp._1, fp._1);
174 |
175 | var step1 = fixmath.MoveTowards(current, target, fp._1);
176 | step1.Should().Be(new fp3(fp._2, fp._1, fp._1));
177 |
178 | var step2 = fixmath.MoveTowards(current, target, fp._10);
179 | step2.Should().Be(new fp3(fp._5, fp._1, fp._1));
180 | }
181 | }
182 | }
--------------------------------------------------------------------------------
/UnitTests/FP_fixmathTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Deterministic;
3 | using Deterministic.FixedPoint;
4 | using FluentAssertions;
5 | using NUnit.Framework;
6 |
7 | namespace UnitTests {
8 | public class FP_fixmathTests {
9 |
10 | [Test]
11 | public void CountLeadingZerosTest() {
12 | fixmath.CountLeadingZeroes(5435345).Should().Be(9);
13 | fixmath.CountLeadingZeroes(4).Should().Be(29);
14 | }
15 |
16 | [Test]
17 | public void ExpTest() {
18 | var from = -5f;
19 | var to = 5f;
20 | var delta = 0.001f;
21 |
22 | for (float v = from; v < to; v += delta) {
23 | var correctAnswer = (float)Math.Exp(v);
24 | var parsedFp = fp.ParseUnsafe(v);
25 | var answer = fixmath.Exp(parsedFp);
26 | answer.AsFloat.Should().BeApproximately(correctAnswer, 0.01f);
27 | }
28 |
29 | from = 5f;
30 | to = 5.33f;
31 | delta = 0.001f;
32 |
33 | for (float v = from; v < to; v += delta) {
34 | var correctAnswer = (float)Math.Exp(v);
35 | var parsedFp = fp.ParseUnsafe(v);
36 | var answer = fixmath.Exp(parsedFp);
37 | answer.AsFloat.Should().BeApproximately(correctAnswer, 1f);
38 | }
39 | }
40 |
41 | [Test]
42 | public void Atan_2Test() {
43 | var from = -1f;
44 | var to = 1f;
45 | var delta = 0.001f;
46 |
47 | for (float v = from; v < to; v += delta) {
48 | var correctAnswer = (float)Math.Atan(v);
49 | var parsedFp = fp.ParseUnsafe(v);
50 | var answer = fixmath.AtanApproximated(parsedFp);
51 | answer.AsFloat.Should().BeApproximately(correctAnswer, 0.01f);
52 | }
53 | }
54 |
55 | [Test]
56 | public void AtanTest() {
57 | var from = -1f;
58 | var to = 1f;
59 | var delta = 0.001f;
60 |
61 | for (float v = from; v < to; v += delta) {
62 | var correctAnswer = (float)Math.Atan(v);
63 | var parsedFp = fp.ParseUnsafe(v);
64 | var answer = fixmath.Atan(parsedFp);
65 | answer.AsFloat.Should().BeApproximately(correctAnswer, 0.001f);
66 | }
67 | }
68 |
69 | [Test]
70 | public void Atan2Test() {
71 | var from1 = 0.1f;
72 | var to1 = 10f;
73 | var from2 = 0.1f;
74 | var to2 = 10f;
75 | var delta = 0.01f;
76 |
77 | for (float x = from1; x < to1; x += delta) {
78 | for (float y = from2; y < to2; y += delta) {
79 | var correctAnswer = (float) Math.Atan2(x, y);
80 | var parsedFp1 = fp.ParseUnsafe(x);
81 | var parsedFp2 = fp.ParseUnsafe(y);
82 | var answer = fixmath.Atan2(parsedFp1, parsedFp2);
83 | answer.AsFloat.Should().BeApproximately(correctAnswer, 0.01f);
84 | }
85 | }
86 | }
87 |
88 | [Test]
89 | public void TanTest() {
90 | for (long i = fp.minus_one.value; i <= fp._1.value; i++) {
91 | fp val;
92 | val.value = i;
93 | var dValue = val.AsDouble;
94 | var answer = fixmath.Tan(val);
95 | answer.AsDouble.Should().BeApproximately(Math.Tan(dValue), 0.001d);
96 | }
97 | }
98 |
99 | [Test]
100 | public void AcosTest() {
101 | for (long i = fp.minus_one.value; i <= fp._1.value; i++) {
102 | fp val;
103 | val.value = i;
104 | var dValue = val.AsDouble;
105 | var answer = fixmath.Acos(val);
106 | answer.AsDouble.Should().BeApproximately(Math.Acos(dValue), 0.0001d);
107 | }
108 | }
109 |
110 | [Test]
111 | public void AsinTest() {
112 | for (long i = fp.minus_one.value; i <= fp._1.value; i++) {
113 | fp val;
114 | val.value = i;
115 | var dValue = val.AsDouble;
116 | var answer = fixmath.Asin(val);
117 | answer.AsDouble.Should().BeApproximately(Math.Asin(dValue), 0.0001d);
118 | }
119 | }
120 |
121 | [Test]
122 | public void CosTest() {
123 | for (long i = -fp.pi.value*2; i <= fp.pi.value*2; i++) {
124 | fp val;
125 | val.value = i;
126 | var dValue = val.AsDouble;
127 | var answer = fixmath.Cos(val);
128 | answer.AsDouble.Should().BeApproximately(Math.Cos(dValue), 0.001d);
129 | }
130 | }
131 |
132 | [Test]
133 | public void SinTest() {
134 | for (long i = -fp.pi.value*2; i <= fp.pi.value*2; i++) {
135 | fp val;
136 | val.value = i;
137 | var dValue = val.AsDouble;
138 | var answer = fixmath.Sin(val);
139 | answer.AsDouble.Should().BeApproximately(Math.Sin(dValue), 0.001d);
140 | }
141 | }
142 |
143 | [Test]
144 | public void SinCosTest() {
145 | for (long i = -fp.pi.value*2; i <= fp.pi.value*2; i++) {
146 | fp val;
147 | val.value = i;
148 | var dValue = val.AsDouble;
149 |
150 | fixmath.SinCos(val, out var sin, out var cos);
151 | sin.AsDouble.Should().BeApproximately(Math.Sin(dValue), 0.001d);
152 | cos.AsDouble.Should().BeApproximately(Math.Cos(dValue), 0.001d);
153 | }
154 | }
155 |
156 | [Test]
157 | public void RcpTest() {
158 | var value = fp._0_25;
159 | var result = fixmath.Rcp(value);
160 | result.Should().Be(fp._4);
161 |
162 | value = fp._4;
163 | result = fixmath.Rcp(value);
164 | result.Should().Be(fp._0_25);
165 | }
166 |
167 | [Test]
168 | public void SqrtTest() {
169 | var from = 0.1f;
170 | var to = 65000;
171 | var delta = 0.1f;
172 |
173 | for (float v = from; v < to; v += delta) {
174 | var correct = (float)Math.Sqrt(v);
175 | var parsedFp = fp.ParseUnsafe(v);
176 | var answer = fixmath.Sqrt(parsedFp);
177 | answer.AsFloat.Should().BeApproximately(correct, 0.01f);
178 | }
179 | }
180 |
181 | [Test]
182 | public void FloorTest() {
183 | var value = fp._0_25;
184 | var result = fixmath.Floor(value);
185 | result.Should().Be(fp._0);
186 |
187 | result = fixmath.Floor(-value);
188 | result.Should().Be(-fp._1);
189 | }
190 |
191 | [Test]
192 | public void CeilTest() {
193 | var value = fp._0_25;
194 | var result = fixmath.Ceil(value);
195 | result.Should().Be(fp._1);
196 |
197 | result = fixmath.Ceil(-fp._4 - fp._0_25);
198 | result.Should().Be(-fp._4);
199 | }
200 |
201 | [Test]
202 | public void RoundToIntTest() {
203 | var value = fp._5 + fp._0_25;
204 | var result = fixmath.RoundToInt(value);
205 | result.Should().Be(5);
206 |
207 | result = fixmath.RoundToInt(value + fp._0_33);
208 | result.Should().Be(6);
209 |
210 | result = fixmath.RoundToInt(value + fp._0_25);
211 | result.Should().Be(6);
212 | }
213 |
214 | [Test]
215 | public void MinTest() {
216 | var value1 = fp._0_25;
217 | var value2 = fp._0_33;
218 | var result = fixmath.Min(value1, value2);
219 | result.Should().Be(value1);
220 |
221 | result = fixmath.Min(-value1, -value2);
222 | result.Should().Be(-value2);
223 | }
224 |
225 | [Test]
226 | public void MaxTest() {
227 | var value1 = fp._0_25;
228 | var value2 = fp._0_33;
229 | var result = fixmath.Max(value1, value2);
230 | result.Should().Be(value2);
231 |
232 | result = fixmath.Max(-value1, -value2);
233 | result.Should().Be(-value1);
234 | }
235 |
236 | [Test]
237 | public void AbsTest() {
238 | var from = -5;
239 | var to = 5;
240 | var delta = 0.1f;
241 |
242 | for (float v = from; v < to; v += delta) {
243 | var correctAnswer = Math.Abs(v);
244 | var parsedFp = fp.ParseUnsafe(v);
245 | var answer = fixmath.Abs(parsedFp);
246 |
247 | answer.AsFloat.Should().BeApproximately(correctAnswer, 0.1f);
248 | }
249 | }
250 |
251 | [Test]
252 | public void ClampTest() {
253 | var from = -5;
254 | var to = 5;
255 | var delta = 0.1f;
256 |
257 | for (float v = from; v < to; v += delta) {
258 | var correctAnswer = Math.Clamp(v, -3, 3);
259 | var parsedFp = fp.ParseUnsafe(v);
260 | var answer = fixmath.Clamp(parsedFp, -fp._3, fp._3);
261 | answer.AsFloat.Should().BeApproximately(correctAnswer, 0.1f);
262 | }
263 | }
264 |
265 |
266 | [Test]
267 | public void LerpTest() {
268 | var result = fixmath.Lerp(fp._2, fp._4, fp._0_25);
269 | result.Should().Be(fp._2 + fp._0_50);
270 |
271 | result = fixmath.Lerp(fp._2, fp._4, fp._0);
272 | result.Should().Be(fp._2);
273 |
274 | result = fixmath.Lerp(fp._2, fp._4, fp._1);
275 | result.Should().Be(fp._4);
276 |
277 | result = fixmath.Lerp(fp._2, fp._4, fp._0_50);
278 | result.Should().Be(fp._3);
279 | }
280 |
281 | [Test]
282 | public void MulTest() {
283 | fp a = 5;
284 |
285 | var result1 = a * fp._0_01;
286 | result1.AsFloat.Should().BeApproximately(0.05f, 0.01f);
287 |
288 | var result2 = fp._0_01 * a;
289 | result2.AsFloat.Should().BeApproximately(0.05f, 0.01f);
290 |
291 | var result3 = fp._0_01 * fp._0_01;
292 | result3.AsFloat.Should().BeApproximately(0.001f, 0.002f);
293 | }
294 |
295 | [Test]
296 | public void SignTest() {
297 | var from = -5;
298 | var to = 5;
299 | var delta = 0.12f;
300 |
301 | for (float v = from; v < to; v += delta) {
302 | var correctAnswer = Math.Sign(v);
303 | var parsedFp = fp.ParseUnsafe(v);
304 | var answer = fixmath.Sign(parsedFp);
305 | answer.AsFloat.Should().BeApproximately(correctAnswer, 0.1f);
306 | }
307 | }
308 |
309 | [Test]
310 | public void IsOppositeSignTest() {
311 | var result = fixmath.IsOppositeSign(fp._0_25, -fp._0_20);
312 | result.Should().Be(true);
313 |
314 | result = fixmath.IsOppositeSign(fp._0_25, fp._0_20);
315 | result.Should().Be(false);
316 |
317 | result = fixmath.IsOppositeSign(-fp._0_25, -fp._0_20);
318 | result.Should().Be(false);
319 | }
320 | }
321 | }
--------------------------------------------------------------------------------
/UnitTests/FP_randomTests.cs:
--------------------------------------------------------------------------------
1 | using Deterministic.FixedPoint;
2 | using FluentAssertions;
3 | using NUnit.Framework;
4 |
5 | namespace UnitTests {
6 | public class FP_randomTests {
7 | [Test]
8 | public void BoolTest()
9 | {
10 | var random = new Random(645);
11 | random.NextBool().Should().Be(true);
12 |
13 | random.SetState(435);
14 | random.NextBool().Should().Be(false);
15 | }
16 |
17 | [Test]
18 | public void IntTest()
19 | {
20 | var random = new Random(645);
21 | random.NextInt().Should().Be(-1975191795);
22 |
23 | random.SetState(435);
24 | random.NextInt().Should().Be(-2030414680);
25 | }
26 |
27 | [Test]
28 | public void IntMaxTest()
29 | {
30 | var random = new Random(345345346);
31 | for (uint i = 5; i < 100; i++) {
32 | random.NextInt(30).Should().BeLessThan(31);
33 | }
34 | }
35 |
36 | [Test]
37 | public void IntMinMaxTest()
38 | {
39 | var random = new Random(345345346);
40 | for (var i = 0; i < 100; i++) {
41 | random.NextInt(-30, 30).Should().BeInRange(-30, 30);
42 | }
43 | }
44 |
45 | [Test]
46 | public void FpTest()
47 | {
48 | var random = new Random(645);
49 | random.NextFp().value.Should().Be(2628L);
50 |
51 | random.SetState(435);
52 | random.NextFp().value.Should().Be(1786L);
53 | }
54 |
55 | [Test]
56 | public void FpMaxTest()
57 | {
58 | var random = new Random(345345346);
59 | for (uint i = 5; i < 100; i++) {
60 | var val = random.NextFp(fp._100);
61 | val.Should().BeLessThan(fp._100);
62 | }
63 | }
64 |
65 | [Test]
66 | public void FpMinMaxTest()
67 | {
68 | var random = new Random(345345346);
69 | for (uint i = 5; i < 100; i++) {
70 | var val = random.NextFp(fp._99, fp._100);
71 | val.Should().BeInRange(fp._99, fp._100);
72 | }
73 | }
74 | }
75 | }
--------------------------------------------------------------------------------
/UnitTests/UnitTests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Library
5 | netcoreapp3.1
6 | FPTesting
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/UnitTests/plotting.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Drawing;
4 | using Deterministic.FixedPoint;
5 | using NUnit.Framework;
6 |
7 | namespace UnitTests {
8 | public class plotting {
9 | [Test]
10 | public void Atan_Plottting() {
11 | var tans = new List();
12 | var correctValue = new List();
13 | var approxValue1 = new List();
14 | var approxValue2 = new List();
15 | var approxValueError1 = new List();
16 | var approxValueError2 = new List();
17 | for (var i = 0; i < 2000; i++) {
18 | var tan = (2 * i / 2000f) - 1;
19 | tans.Add(tan);
20 | }
21 |
22 | foreach (var tan in tans) {
23 | var correctTan = Math.Atan(tan);
24 | correctValue.Add(correctTan);
25 | var aprox1Tan = fixmath.Atan(fp.ParseUnsafe((float) tan)).AsDouble;
26 | approxValue1.Add(aprox1Tan);
27 | approxValueError1.Add(correctTan - aprox1Tan);
28 | var aprox2Tan = fixmath.AtanApproximated(fp.ParseUnsafe((float) tan)).AsDouble;
29 | approxValue2.Add(aprox2Tan);
30 | approxValueError2.Add(correctTan - aprox2Tan);
31 | }
32 |
33 | var plt = new ScottPlot.Plot(2048, 2048);
34 | plt.PlotScatter(tans.ToArray(), correctValue.ToArray(), Color.CadetBlue, 0.01f, 1, "Math.Atan");
35 | plt.PlotScatter(tans.ToArray(), approxValue1.ToArray(), Color.Firebrick, 0.01f, 1f, "fixmath.Atan");
36 | plt.PlotScatter(tans.ToArray(), approxValue2.ToArray(), Color.FromArgb(74, 178, 67), 0.01f, 1, "fixmath.Atan_2");
37 | plt.AxisAuto();
38 | plt.SaveFig("Atan.png");
39 |
40 | plt = new ScottPlot.Plot(2048, 2048);
41 | plt.PlotScatter(tans.ToArray(), approxValueError1.ToArray(), Color.Firebrick, 0.01f, 1f, "fixmath.Atan");
42 | plt.PlotScatter(tans.ToArray(), approxValueError2.ToArray(), Color.FromArgb(74, 178, 67), 0.01f, 1, "fixmath.Atan_2");
43 | plt.AxisAuto();
44 | plt.SaveFig("Atan_error.png");
45 | }
46 |
47 | [Test]
48 | public void Atan2_Plottting() {
49 | var xValues = new List();
50 | var correctValue = new List();
51 | var approxValue1 = new List();
52 | var approxValueError1 = new List();
53 | for (var i = 0; i < 2000; i++) {
54 | var tan = (2 * i / 2000f) - 1;
55 | xValues.Add(tan);
56 | }
57 |
58 | foreach (var tan in xValues) {
59 | var correctTan = Math.Atan2(tan, 1);
60 | correctValue.Add(correctTan);
61 | var aprox1Tan = fixmath.Atan2(fp.ParseUnsafe((float) tan), fp._1).AsDouble;
62 | approxValue1.Add(aprox1Tan);
63 | approxValueError1.Add(correctTan - aprox1Tan);
64 | }
65 |
66 | var plt = new ScottPlot.Plot(2048, 2048);
67 | plt.PlotScatter(xValues.ToArray(), correctValue.ToArray(), Color.CadetBlue, 0.01f, 1, "Math.Atan2");
68 | plt.PlotScatter(xValues.ToArray(), approxValue1.ToArray(), Color.Firebrick, 0.01f, 1f, "fixmath.Atan2");
69 | plt.AxisAuto();
70 | plt.SaveFig("Atan2.png");
71 |
72 | plt = new ScottPlot.Plot(2048, 2048);
73 | plt.PlotScatter(xValues.ToArray(), approxValueError1.ToArray(), Color.Firebrick, 0.01f, 1f, "fixmath.Atan2");
74 | plt.AxisAuto();
75 | plt.SaveFig("Atan2_error.png");
76 | }
77 | }
78 | }
--------------------------------------------------------------------------------