Normally, this would be done with streams in higher level languages, but .Net framework exposes a way to do so without intermediate stream objects using Marshal.
Imports System.Runtime.InteropServices
Module Module1
Sub Main()
Dim given As Int16 = -20
Dim buffer As IntPtr = Marshal.AllocCoTaskMem(Marshal.SizeOf(given))
Marshal.StructureToPtr(given, buffer, False)
Dim result As UInt16 = Marshal.PtrToStructure(buffer, GetType(UInt16))
MsgBox(result)
End Sub
End Module
To my surprise, Using Marshal seems to be more efficient than using Math, based on the stats I got
4 seconds of v1 yielded: 2358173 conversions
4 seconds of v2 yielded: 4069878 conversions
from test:
Imports System.Runtime.InteropServices
Module Module1
Function v1(given As Int16) As UInt16
Dim buffer As IntPtr = Marshal.AllocCoTaskMem(Marshal.SizeOf(given))
Marshal.StructureToPtr(given, buffer, False)
Dim result As UInt16 = Marshal.PtrToStructure(buffer, GetType(UInt16))
v1 = result
End Function
Function v2(given As Int16) As UInt16
If given < 0 Then
given = (Not given) + 1
End If
v2 = given
End Function
Sub Main()
Dim total0 As Integer
Dim total1 As Integer
Dim t0 As DateTime = DateTime.Now()
While ((DateTime.Now() - t0).TotalSeconds() < 4)
v1(-Rnd() * Int16.MaxValue)
total0 = total0 + 1
End While
Console.WriteLine("4 seconds of v1 yielded: " & total0 & " conversions")
t0 = DateTime.Now()
While ((DateTime.Now() - t0).TotalSeconds() < 4)
v2(-Rnd() * Int16.MaxValue)
total1 = total1 + 1
End While
Console.WriteLine("4 seconds of v2 yielded: " & total1 & " conversions")
Console.ReadKey()
End Sub
End Module
Stranger still, Marshal approach seems negligibly as effective as C# style cast. On my first run, marshal approach was slower, but on second run, marshal approach was faster. This is the result of the second run
4 seconds of v1 yielded: 1503403 conversions
4 seconds of v2 yielded: 1240585 conversions
4 seconds of v3 yielded: 1592731 conversions
using this code
using System;
using System.Runtime.InteropServices;
class Program
{
static DateTime startTime = DateTime.Now;
static double time {
get {
return (DateTime.Now - startTime).TotalMilliseconds;
}
}
static ushort v1(short given) {
if (given > 0) {
return (ushort)given;
}
return (ushort)(~given + 1);
}
static ushort v2(short given) {
var buffer = Marshal.AllocCoTaskMem(Marshal.SizeOf(given));
Marshal.StructureToPtr(given, buffer, false);
ushort result = (ushort)Marshal.PtrToStructure(buffer, typeof(ushort));
return result;
}
static ushort v3(short given)
{
return (ushort)given;
}
static void Main(string[] args)
{
int total0 = 0;
int total1 = 0;
int total2 = 0;
double t0;
t0 = time;
while (time - t0 < 4000) {
v1((short)(-new Random().NextDouble() * Int16.MaxValue));
++total0;
}
Console.WriteLine("4 seconds of v1 yielded: " + total0 + " conversions");
t0 = time;
while (time - t0 < 4000) {
v2((short)(-new Random().NextDouble() * Int16.MaxValue));
++total1;
}
Console.WriteLine("4 seconds of v2 yielded: " + total1 + " conversions");
t0 = time;
while (time - t0 < 4000) {
v3((short)(-new Random().NextDouble() * Int16.MaxValue));
++total2;
}
Console.WriteLine("4 seconds of v3 yielded: " + total2 + " conversions");
Console.ReadKey();
}
}
Now to bring in the king;
// ConsoleApplication3.cpp : main project file.
#include "stdafx.h"
using namespace System;
using namespace System::Runtime::InteropServices;
unsigned __int16 v4(__int16 given) {
return (unsigned __int16)given;
}
public ref class Program
{
public:
static DateTime startTime = DateTime::Now;
static property double time {
double get() {
return (DateTime::Now - startTime).TotalMilliseconds;
}
}
static UInt16 v1(Int16 given) {
if (given > 0) {
return given;
}
return (UInt16)(~given + 1);
}
static UInt16 v2(Int16 given) {
IntPtr buffer = Marshal::AllocCoTaskMem(Marshal::SizeOf(given));
Marshal::StructureToPtr(given, buffer, false);
Type ^t = UInt16::typeid;
UInt16 result = (UInt16)Marshal::PtrToStructure(buffer, t);
return result;
}
static UInt16 v3(Int16 given)
{
return (UInt16)given;
}
typedef String ^string;
static void _Main(array<string> ^args)
{
int total0 = 0;
int total1 = 0;
int total2 = 0;
int total3 = 0;
double t0;
t0 = time;
while (time - t0 < 4000) {
Double d = (gcnew Random())->NextDouble();
v1((short)(-d * Int16::MaxValue));
++total0;
}
Console::WriteLine("4 seconds of v1 yielded: " + total0 + " conversions");
t0 = time;
while (time - t0 < 4000) {
v2((short)(-((gcnew Random())->NextDouble()) * Int16::MaxValue));
++total1;
}
Console::WriteLine("4 seconds of v2 yielded: " + total1 + " conversions");
t0 = time;
while (time - t0 < 4000) {
v3((short)(-((gcnew Random())->NextDouble()) * Int16::MaxValue));
++total2;
}
Console::WriteLine("4 seconds of v3 yielded: " + total2 + " conversions");
t0 = time;
while (time - t0 < 4000) {
v4((short)(-((gcnew Random())->NextDouble()) * Int16::MaxValue));
++total3;
}
Console::WriteLine("4 seconds of v4 yielded: " + total3 + " conversions");
Console::ReadKey();
}
};
int main(array<System::String ^> ^args)
{
Program::_Main(args);
return 0;
}
well, the results are pretty interesting
4 seconds of v1 yielded: 1417901 conversions
4 seconds of v2 yielded: 967417 conversions
4 seconds of v3 yielded: 1624141 conversions
4 seconds of v4 yielded: 1627827 conversions
checked
/unchecked
keyword away... – Steadfast