Lightly tested.
return error;
}
+int Fixed128_str2_cs(struct Fixed128 *r, const char *s) {
+ char *endptr;
+ int rc = Fixed128_str2(r, s, &endptr);
+ if(rc == 0) {
+ if(endptr == s || *endptr)
+ return FIXED128_STR_FORMAT;
+ else
+ return FIXED128_STR_OK;
+ } else
+ return FIXED128_STR_RANGE;
+}
+
/*
Local Variables:
mode:c
int base);
LIBMANDY_API int Fixed128_str2(struct Fixed128 *r, const char *s, char **endptr);
+ LIBMANDY_API int Fixed128_str2_cs(struct Fixed128 *r, const char *s);
+#define FIXED128_STR_OK 0
+#define FIXED128_STR_RANGE 1
+#define FIXED128_STR_FORMAT 2
+
LIBMANDY_API void Fixed128_double2(struct Fixed128 *r, double n);
LIBMANDY_API double Fixed128_2double(const struct Fixed128 *a);
LIBMANDY_API long double Fixed128_2longdouble(const struct Fixed128 *a);
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {E5DDECA6-1F6C-401B-BBB6-1101B1F5B61D}.Debug|Any CPU.ActiveCfg = Debug|Win32
- {E5DDECA6-1F6C-401B-BBB6-1101B1F5B61D}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
- {E5DDECA6-1F6C-401B-BBB6-1101B1F5B61D}.Debug|Mixed Platforms.Build.0 = Debug|Win32
+ {E5DDECA6-1F6C-401B-BBB6-1101B1F5B61D}.Debug|Any CPU.ActiveCfg = Debug|x64
+ {E5DDECA6-1F6C-401B-BBB6-1101B1F5B61D}.Debug|Any CPU.Build.0 = Debug|x64
+ {E5DDECA6-1F6C-401B-BBB6-1101B1F5B61D}.Debug|Mixed Platforms.ActiveCfg = Debug|x64
+ {E5DDECA6-1F6C-401B-BBB6-1101B1F5B61D}.Debug|Mixed Platforms.Build.0 = Debug|x64
{E5DDECA6-1F6C-401B-BBB6-1101B1F5B61D}.Debug|Win32.ActiveCfg = Debug|Win32
{E5DDECA6-1F6C-401B-BBB6-1101B1F5B61D}.Debug|Win32.Build.0 = Debug|Win32
{E5DDECA6-1F6C-401B-BBB6-1101B1F5B61D}.Debug|x64.ActiveCfg = Debug|x64
{E5DDECA6-1F6C-401B-BBB6-1101B1F5B61D}.Release|Win32.Build.0 = Release|Win32
{E5DDECA6-1F6C-401B-BBB6-1101B1F5B61D}.Release|x64.ActiveCfg = Release|x64
{E5DDECA6-1F6C-401B-BBB6-1101B1F5B61D}.Release|x64.Build.0 = Release|x64
- {15F60354-A2F4-4C39-91E1-656DA501CE79}.Debug|Any CPU.ActiveCfg = Debug|Win32
- {15F60354-A2F4-4C39-91E1-656DA501CE79}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
- {15F60354-A2F4-4C39-91E1-656DA501CE79}.Debug|Mixed Platforms.Build.0 = Debug|Win32
+ {15F60354-A2F4-4C39-91E1-656DA501CE79}.Debug|Any CPU.ActiveCfg = Debug|x64
+ {15F60354-A2F4-4C39-91E1-656DA501CE79}.Debug|Any CPU.Build.0 = Debug|x64
+ {15F60354-A2F4-4C39-91E1-656DA501CE79}.Debug|Mixed Platforms.ActiveCfg = Debug|x64
+ {15F60354-A2F4-4C39-91E1-656DA501CE79}.Debug|Mixed Platforms.Build.0 = Debug|x64
{15F60354-A2F4-4C39-91E1-656DA501CE79}.Debug|Win32.ActiveCfg = Debug|Win32
{15F60354-A2F4-4C39-91E1-656DA501CE79}.Debug|Win32.Build.0 = Debug|Win32
{15F60354-A2F4-4C39-91E1-656DA501CE79}.Debug|x64.ActiveCfg = Debug|x64
{15F60354-A2F4-4C39-91E1-656DA501CE79}.Release|Win32.Build.0 = Release|Win32
{15F60354-A2F4-4C39-91E1-656DA501CE79}.Release|x64.ActiveCfg = Release|x64
{15F60354-A2F4-4C39-91E1-656DA501CE79}.Release|x64.Build.0 = Release|x64
- {8A51A96E-3178-4E07-8ADC-31613CFFC2BD}.Debug|Any CPU.ActiveCfg = Debug|Win32
- {8A51A96E-3178-4E07-8ADC-31613CFFC2BD}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
- {8A51A96E-3178-4E07-8ADC-31613CFFC2BD}.Debug|Mixed Platforms.Build.0 = Debug|Win32
+ {8A51A96E-3178-4E07-8ADC-31613CFFC2BD}.Debug|Any CPU.ActiveCfg = Debug|x64
+ {8A51A96E-3178-4E07-8ADC-31613CFFC2BD}.Debug|Any CPU.Build.0 = Debug|x64
+ {8A51A96E-3178-4E07-8ADC-31613CFFC2BD}.Debug|Mixed Platforms.ActiveCfg = Debug|x64
+ {8A51A96E-3178-4E07-8ADC-31613CFFC2BD}.Debug|Mixed Platforms.Build.0 = Debug|x64
{8A51A96E-3178-4E07-8ADC-31613CFFC2BD}.Debug|Win32.ActiveCfg = Debug|Win32
{8A51A96E-3178-4E07-8ADC-31613CFFC2BD}.Debug|Win32.Build.0 = Debug|Win32
{8A51A96E-3178-4E07-8ADC-31613CFFC2BD}.Debug|x64.ActiveCfg = Debug|x64
{8A51A96E-3178-4E07-8ADC-31613CFFC2BD}.Release|Win32.Build.0 = Release|Win32
{8A51A96E-3178-4E07-8ADC-31613CFFC2BD}.Release|x64.ActiveCfg = Release|x64
{8A51A96E-3178-4E07-8ADC-31613CFFC2BD}.Release|x64.Build.0 = Release|x64
- {51AC3A69-21F2-4E24-B5AD-289F1EE8FCFE}.Debug|Any CPU.ActiveCfg = Debug|Win32
- {51AC3A69-21F2-4E24-B5AD-289F1EE8FCFE}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
- {51AC3A69-21F2-4E24-B5AD-289F1EE8FCFE}.Debug|Mixed Platforms.Build.0 = Debug|Win32
+ {51AC3A69-21F2-4E24-B5AD-289F1EE8FCFE}.Debug|Any CPU.ActiveCfg = Debug|x64
+ {51AC3A69-21F2-4E24-B5AD-289F1EE8FCFE}.Debug|Any CPU.Build.0 = Debug|x64
+ {51AC3A69-21F2-4E24-B5AD-289F1EE8FCFE}.Debug|Mixed Platforms.ActiveCfg = Debug|x64
+ {51AC3A69-21F2-4E24-B5AD-289F1EE8FCFE}.Debug|Mixed Platforms.Build.0 = Debug|x64
{51AC3A69-21F2-4E24-B5AD-289F1EE8FCFE}.Debug|Win32.ActiveCfg = Debug|Win32
{51AC3A69-21F2-4E24-B5AD-289F1EE8FCFE}.Debug|Win32.Build.0 = Debug|Win32
{51AC3A69-21F2-4E24-B5AD-289F1EE8FCFE}.Debug|x64.ActiveCfg = Debug|x64
--- /dev/null
+\feffusing System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Runtime.InteropServices;
+
+namespace uk.org.greenend.mandy
+{
+ /// <summary>
+ /// 128-bit fixed point arithmetic
+ /// </summary>
+ /// <remarks><para>You get 32 bits of integer part and 96 bit of fractional part.</para></remarks>
+ [StructLayout(LayoutKind.Sequential)]
+ public struct Fixed128
+ {
+ /// <summary>
+ /// Three fractional words and the integer part
+ /// </summary>
+ /// <remarks><para>Negative values are indicate using two's complement.</para></remarks>
+ public uint f3, f2, f1, i;
+
+ /// <summary>
+ /// Constructor
+ /// </summary>
+ /// <param name="i">Integer part</param>
+ /// <param name="f1">Top 32 bits of fractional part</param>
+ /// <param name="f2">Middle 32 bits of fractional part</param>
+ /// <param name="f3">Bottom 32 bits of fractional part</param>
+ public Fixed128(int i, uint f1, uint f2, uint f3)
+ {
+ this.i = (uint)i;
+ this.f1 = f1;
+ this.f2 = f2;
+ this.f3 = f3;
+ }
+
+ #region Conversions
+
+ /// <summary>
+ /// Cast from an int.
+ /// </summary>
+ /// <param name="n">Integer value</param>
+ /// <returns>Converted value</returns>
+ public static implicit operator Fixed128(int n)
+ {
+ return new Fixed128(n, 0, 0, 0);
+ }
+
+ public static implicit operator Fixed128(string s)
+ {
+ Fixed128 r = 0;
+ int error = Fixed128_str2_cs(ref r, s);
+ switch(error)
+ {
+ case 0: // FIXED128_STR_OK
+ break;
+ case 1: // FIXED128_STR_RANGE
+ throw new FormatException("number out of range"); // TODO better choice?
+ case 2: // FIXED128_STR_FORMAT
+ throw new FormatException("invalid numeric format"); // TODO better choice?
+ }
+ return r;
+ }
+
+ public unsafe static implicit operator string(Fixed128 n)
+ {
+ const int BUFSIZE = 256;
+ byte* buffer = stackalloc byte[BUFSIZE];
+ Fixed128_2str(buffer, (IntPtr)BUFSIZE, ref n, 10);
+ return Marshal.PtrToStringAnsi((IntPtr)buffer);
+ }
+
+ public static implicit operator double(Fixed128 n)
+ {
+ return Fixed128_2double(ref n);
+ }
+
+ public static implicit operator Fixed128(double n)
+ {
+ Fixed128 r = 0;
+ Fixed128_double2(ref r, n);
+ return r;
+ }
+
+ #endregion
+
+ #region Operations
+
+ public static Fixed128 operator +(Fixed128 a, Fixed128 b)
+ {
+ Fixed128 r = 0;
+ Fixed128_add(ref r, ref a, ref b);
+ return r;
+ }
+
+ public static Fixed128 operator -(Fixed128 a, Fixed128 b)
+ {
+ Fixed128 r = 0;
+ Fixed128_sub(ref r, ref a, ref b);
+ return r;
+ }
+
+ public static Fixed128 operator *(Fixed128 a, Fixed128 b)
+ {
+ Fixed128 r = 0;
+ Fixed128_mul(ref r, ref a, ref b);
+ return r;
+ }
+
+ public static Fixed128 operator /(Fixed128 a, Fixed128 b)
+ {
+ Fixed128 r = 0;
+ Fixed128_div(ref r, ref a, ref b);
+ return r;
+ }
+
+ public static Fixed128 operator-(Fixed128 a)
+ {
+ Fixed128 r = 0;
+ Fixed128_neg(ref r, ref a);
+ return r;
+ }
+
+ public Fixed128 sqrt()
+ {
+ Fixed128 r = 0;
+ Fixed128_sqrt(ref r, ref this);
+ return r;
+ }
+
+ public static bool operator ==(Fixed128 a, Fixed128 b)
+ {
+ return Fixed128_eq(ref a, ref b) != 0;
+ }
+
+ public static bool operator !=(Fixed128 a, Fixed128 b)
+ {
+ return Fixed128_eq(ref a, ref b) == 0;
+ }
+
+ public static bool operator <(Fixed128 a, Fixed128 b)
+ {
+ return Fixed128_lt(ref a, ref b) != 0;
+ }
+
+ public static bool operator >=(Fixed128 a, Fixed128 b)
+ {
+ return Fixed128_lt(ref a, ref b) == 0;
+ }
+
+ public static bool operator >(Fixed128 a, Fixed128 b)
+ {
+ return Fixed128_lt(ref b, ref a) != 0;
+ }
+
+ public static bool operator <=(Fixed128 a, Fixed128 b)
+ {
+ return Fixed128_lt(ref b, ref a) == 0;
+ }
+
+ #endregion
+
+ #region Unmanaged code
+
+ [DllImport("libmandy.dll")]
+ private static extern void Fixed128_add(ref Fixed128 r,
+ ref Fixed128 a,
+ ref Fixed128 b);
+
+ [DllImport("libmandy.dll")]
+ private static extern void Fixed128_sub(ref Fixed128 r,
+ ref Fixed128 a,
+ ref Fixed128 b);
+
+ [DllImport("libmandy.dll")]
+ private static extern void Fixed128_mul(ref Fixed128 r,
+ ref Fixed128 a,
+ ref Fixed128 b);
+
+ [DllImport("libmandy.dll")]
+ private static extern void Fixed128_div(ref Fixed128 r,
+ ref Fixed128 a,
+ ref Fixed128 b);
+
+ [DllImport("libmandy.dll")]
+ private static extern void Fixed128_neg(ref Fixed128 r,
+ ref Fixed128 a);
+
+ [DllImport("libmandy.dll")]
+ private static extern void Fixed128_sqrt(ref Fixed128 r,
+ ref Fixed128 a);
+
+ [DllImport("libmandy.dll")]
+ private static extern int Fixed128_eq(ref Fixed128 r,
+ ref Fixed128 a);
+
+ [DllImport("libmandy.dll")]
+ private static extern int Fixed128_lt(ref Fixed128 r,
+ ref Fixed128 a);
+
+ [DllImport("libmandy.dll")]
+ private static extern int Fixed128_str2_cs(ref Fixed128 r, string s);
+
+ [DllImport("libmandy.dll")]
+ private unsafe static extern IntPtr Fixed128_2str(byte *buffer, IntPtr bufsize,
+ ref Fixed128 a, int radix);
+
+ [DllImport("libmandy.dll")]
+ private static extern void Fixed128_double2(ref Fixed128 r, double n);
+
+ [DllImport("libmandy.dll")]
+ private static extern double Fixed128_2double(ref Fixed128 a);
+
+ #endregion
+
+ }
+}
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
+ <PlatformTarget>x64</PlatformTarget>
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
+ <PlatformTarget>x64</PlatformTarget>
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
+ <Compile Include="Fixed128.cs" />
<Compile Include="JobQueue.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
--- /dev/null
+\feffusing System;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using uk.org.greenend.mandy;
+
+namespace tests
+{
+ /// <summary>
+ /// Tests for Fix128
+ /// </summary>
+ /// <remarks><para>These tests aren't particularly exhaustive;
+ /// use fixed128-test for more exhaustive (and portable) testing.</para>
+ /// <para>Only the 64-bit configuration is testable.</para></remarks>
+ [TestClass]
+ [DeploymentItem(@"..\..\..\..\x64\Debug\libmandy.dll")]
+ public class Fixed128Test
+ {
+ [TestMethod]
+ public void AddTest()
+ {
+ Fixed128 a = 1;
+ Fixed128 b = 2;
+ Fixed128 r = a + b;
+ Assert.AreEqual(3u, r.i);
+ Assert.AreEqual(0u, r.f1);
+ Assert.AreEqual(0u, r.f2);
+ Assert.AreEqual(0u, r.f3);
+ }
+
+ [TestMethod]
+ public void SubTest()
+ {
+ Fixed128 a = 1;
+ Fixed128 b = 2;
+ Fixed128 r = a - b;
+ Assert.AreEqual(0xFFFFFFFFu, r.i);
+ Assert.AreEqual(0u, r.f1);
+ Assert.AreEqual(0u, r.f2);
+ Assert.AreEqual(0u, r.f3);
+ }
+
+ [TestMethod]
+ public void MulTest()
+ {
+ Fixed128 a = 3;
+ Fixed128 b = 5;
+ Fixed128 r = a * b;
+ Assert.AreEqual(15u, r.i);
+ Assert.AreEqual(0u, r.f1);
+ Assert.AreEqual(0u, r.f2);
+ Assert.AreEqual(0u, r.f3);
+ a = -3;
+ b = -5;
+ r = a * b;
+ Assert.AreEqual(15u, r.i);
+ Assert.AreEqual(0u, r.f1);
+ Assert.AreEqual(0u, r.f2);
+ Assert.AreEqual(0u, r.f3);
+ a = 3;
+ b = -5;
+ r = a * b;
+ Assert.AreEqual(0xFFFFFFF1u, r.i);
+ Assert.AreEqual(0u, r.f1);
+ Assert.AreEqual(0u, r.f2);
+ Assert.AreEqual(0u, r.f3);
+ }
+
+ [TestMethod]
+ public void DivTest()
+ {
+ Fixed128 a = 3;
+ Fixed128 b = 2;
+ Fixed128 r = a / b;
+ Assert.AreEqual(1u, r.i);
+ Assert.AreEqual(0x80000000u, r.f1);
+ Assert.AreEqual(0u, r.f2);
+ Assert.AreEqual(0u, r.f3);
+ }
+
+ [TestMethod]
+ public void NegTest()
+ {
+ Fixed128 a = 100;
+ Fixed128 r = -a;
+ Assert.AreEqual(0xFFFFFF9Cu, r.i);
+ Assert.AreEqual(0u, r.f1);
+ Assert.AreEqual(0u, r.f2);
+ Assert.AreEqual(0u, r.f3);
+ r = -r;
+ Assert.AreEqual(100u, r.i);
+ Assert.AreEqual(0u, r.f1);
+ Assert.AreEqual(0u, r.f2);
+ Assert.AreEqual(0u, r.f3);
+ }
+
+ [TestMethod]
+ public void SqrtTest()
+ {
+ Fixed128 a = 100;
+ Fixed128 r = a.sqrt();
+ Assert.AreEqual(10u, r.i);
+ Assert.AreEqual(0u, r.f1);
+ Assert.AreEqual(0u, r.f2);
+ Assert.AreEqual(0u, r.f3);
+ a = 2;
+ r = a.sqrt();
+ Assert.AreEqual(1u, r.i);
+ Assert.AreEqual(0x6a09e667u, r.f1);
+ Assert.AreEqual(0xf3bcc908u, r.f2);
+ Assert.AreEqual(0xb2fb1367u, r.f3);
+ }
+
+ [TestMethod]
+ public void FromDecimalTest()
+ {
+ Fixed128 a = "1";
+ Assert.AreEqual(1u, a.i);
+ Assert.AreEqual(0u, a.f1);
+ Assert.AreEqual(0u, a.f2);
+ Assert.AreEqual(0u, a.f3);
+ a = "400.125";
+ Assert.AreEqual(400u, a.i);
+ Assert.AreEqual(0x20000000u, a.f1);
+ Assert.AreEqual(0u, a.f2);
+ Assert.AreEqual(0u, a.f3);
+ }
+
+ [TestMethod]
+ public void ToDecimalTest()
+ {
+ Fixed128 a = 3;
+ string s = (string)a;
+ Assert.AreEqual("3", s);
+ a /= (Fixed128)2;
+ s = (string)a;
+ Assert.AreEqual("1.5", s);
+ }
+
+ [TestMethod]
+ public void FromDoubleTest()
+ {
+ Fixed128 a = 1.5;
+ Assert.AreEqual(1u, a.i);
+ Assert.AreEqual(0x80000000u, a.f1);
+ Assert.AreEqual(0u, a.f2);
+ Assert.AreEqual(0u, a.f3);
+ a = -100.125;
+ Assert.AreEqual(0xFFFFFF9Bu, a.i);
+ Assert.AreEqual(0xE0000000u, a.f1);
+ Assert.AreEqual(0u, a.f2);
+ Assert.AreEqual(0u, a.f3);
+ }
+
+ [TestMethod]
+ public void ToDoubleTest()
+ {
+ Fixed128 a = new Fixed128(1, 0x80000000u, 0u, 0u);
+ double n = a;
+ Assert.AreEqual(1.5, n);
+ a = new Fixed128(-101, 0xE0000000u, 0u, 0u);
+ n = a;
+ Assert.AreEqual(-100.125, n);
+ }
+ }
+}
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
+ <PlatformTarget>x64</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
+ <PlatformTarget>x64</PlatformTarget>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<ItemGroup>
<Compile Include="JobQueueTest.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
+ <Compile Include="Fixed128Test.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\mandycs\mandycs.csproj">