My requirements are simple:
Be able to define dimensions of bit array, i.e: 5 bytes.
bool Get(bitIndex: int)
Set(bitIndex: int)
Is there a c# equivalent which provides similar functionality to BitSet in Java?
Here's the scenario:
Initialize 5 bytes, all bits are 0(false).
Set byte 3, bit 8 to TRUE.
Get status of byte 3, bit 8.
UPDATE: Solution from Michael Bray:
static void Main(string[] args)
{
// Set for 5 bytes
BitArray ba = new BitArray(8 * 5);
// Set bit #1 on byte #4
ba.Set(GetBitNum(4, 1), true);
// Get bit #1 on byte #4
bool v = ba.Get(GetBitNum(4, 1));
}
static int GetBitNum(int byteNum, int bitNum) // Assumes index starts at 1
{
return (byteNum - 1) * 8 + (bitNum - 1);
}
System.Collections.BitArray is pretty close, but it's a bit lacking in features. I wrote a helper class that implements a lot of features you might need for BitArray some time ago, but I'd have to dig it up. Let me know if you think you need it.
EDIT: As requested in the comments below, I've posted the code at http://pastebin.com/GLyzcUZC. As I discuss, though, it's benefits over stock BitArray are minimal, as I wrote it for some specific needs that I had. Do with it as you wish.
EDIT 2: As Miguel pointed out in the comments, there are some implementation issues that make my 'BitArray' code not so good... I had already realized the deficiencies and had re-written a new version called BoolArray (to distinguish from BitArray) that doesn't suffer from those problems :
namespace Utils
{
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Threading;
/// <summary>
/// A replacement for BitArray
/// </summary>
public class BoolArray : IEnumerable, ICollection, ICloneable
{
private UInt32[] bits = null;
private int _length = 0;
private static UInt32 ONE = (UInt32)1 << 31;
private object _syncRoot;
private static Func<byte[], byte[]> EndianFixer = null;
#region Constructors
static BoolArray()
{
if (BitConverter.IsLittleEndian) EndianFixer = (a) => a.Reverse().ToArray();
else EndianFixer = (a) => a;
}
public BoolArray(BoolArray srcBits)
{
this.InitializeFrom(srcBits.ToArray());
}
public BoolArray(BitArray srcBits)
{
this._length = srcBits.Count;
this.bits = new UInt32[RequiredSize(this._length)];
for (int i = 0; i < srcBits.Count; i++) this[i] = srcBits[i];
}
public BoolArray(int v)
{
ICollection<byte> bytes = EndianFixer(BitConverter.GetBytes(v)).ToList();
InitializeFrom(bytes);
}
public BoolArray(ICollection<bool> srcBits)
{
this.InitializeFrom(srcBits.ToArray());
}
public BoolArray(ICollection<byte> srcBits)
{
InitializeFrom(srcBits);
}
public BoolArray(ICollection<short> srcBits)
{
ICollection<byte> bytes = srcBits.SelectMany(v => EndianFixer(BitConverter.GetBytes(v))).ToList();
InitializeFrom(bytes);
}
public BoolArray(ICollection<ushort> srcBits)
{
ICollection<byte> bytes = srcBits.SelectMany(v => EndianFixer(BitConverter.GetBytes(v))).ToList();
InitializeFrom(bytes);
}
public BoolArray(ICollection<int> srcBits)
{
ICollection<byte> bytes = srcBits.SelectMany(v => EndianFixer(BitConverter.GetBytes(v))).ToList();
InitializeFrom(bytes);
}
public BoolArray(ICollection<uint> srcBits)
{
ICollection<byte> bytes = srcBits.SelectMany(v => EndianFixer(BitConverter.GetBytes(v))).ToList();
InitializeFrom(bytes);
}
public BoolArray(ICollection<long> srcBits)
{
ICollection<byte> bytes = srcBits.SelectMany(v => EndianFixer(BitConverter.GetBytes(v))).ToList();
InitializeFrom(bytes);
}
public BoolArray(ICollection<ulong> srcBits)
{
ICollection<byte> bytes = srcBits.SelectMany(v => EndianFixer(BitConverter.GetBytes(v))).ToList();
InitializeFrom(bytes);
}
public BoolArray(int capacity, bool defaultValue = false)
{
this.bits = new UInt32[RequiredSize(capacity)];
this._length = capacity;
// Only need to do this if true, because default for all bits is false
if (defaultValue) for (int i = 0; i < this._length; i++) this[i] = true;
}
private void InitializeFrom(ICollection<byte> srcBits)
{
this._length = srcBits.Count * 8;
this.bits = new UInt32[RequiredSize(this._length)];
for (int i = 0; i < srcBits.Count; i++)
{
uint bv = srcBits.Skip(i).Take(1).Single();
for (int b = 0; b < 8; b++)
{
bool bitVal = ((bv << b) & 0x0080) != 0;
int bi = 8 * i + b;
this[bi] = bitVal;
}
}
}
private void InitializeFrom(ICollection<bool> srcBits)
{
this._length = srcBits.Count;
this.bits = new UInt32[RequiredSize(this._length)];
int index = 0;
foreach (var b in srcBits) this[index++] = b;
}
private static int RequiredSize(int bitCapacity)
{
return (bitCapacity + 31) >> 5;
}
#endregion
public bool this[int index]
{
get
{
if (index >= _length) throw new IndexOutOfRangeException();
int byteIndex = index >> 5;
int bitIndex = index & 0x1f;
return ((bits[byteIndex] << bitIndex) & ONE) != 0;
}
set
{
if (index >= _length) throw new IndexOutOfRangeException();
int byteIndex = index >> 5;
int bitIndex = index & 0x1f;
if (value) bits[byteIndex] |= (ONE >> bitIndex);
else bits[byteIndex] &= ~(ONE >> bitIndex);
}
}
#region Interfaces implementation
#region IEnumerable
public IEnumerator GetEnumerator()
{
//for (int i = 0; i < _length; i++) yield return this[i];
return this.ToArray().GetEnumerator();
}
#endregion
#region ICollection
public void CopyTo(Array array, int index)
{
if (array == null) throw new ArgumentNullException("array");
if (index < 0) throw new ArgumentOutOfRangeException("index");
if (array.Rank != 1) throw new ArgumentException("Multidimensional array not supported");
if (array is UInt32[]) Array.Copy(this.bits, 0, array, index, (this.Count + sizeof(UInt32) - 1) / sizeof(UInt32));
else if (array is bool[]) Array.Copy(this.ToArray(), 0, array, index, this.Count);
else throw new ArgumentException("Array type not supported (UInt32[] or bool[] only)");
}
public int Count
{
get { return this._length; }
private set
{
if (value > this._length) Extend(value - this._length);
else this._length = Math.Max(0, value);
}
}
public bool IsSynchronized
{
get { return false; }
}
public object SyncRoot
{
get
{
if (this._syncRoot == null) Interlocked.CompareExchange<object>(ref this._syncRoot, new object(), null);
return _syncRoot;
}
}
#endregion
#region ICloneable
public object Clone()
{
return new BoolArray(this);
}
// Not part of ICloneable, but better - returns a strongly-typed result
public BoolArray Dup()
{
return new BoolArray(this);
}
#endregion
#endregion
#region String Conversions
public override string ToString()
{
return ToBinaryString();
//return ToHexString(" ", " ■ ");
}
public static BoolArray FromHexString(string hex)
{
if (hex == null) throw new ArgumentNullException("hex");
List<bool> bits = new List<bool>();
for (int i = 0; i < hex.Length; i++)
{
int b = byte.Parse(hex[i].ToString(), NumberStyles.HexNumber);
bits.Add((b >> 3) == 1);
bits.Add(((b & 0x7) >> 2) == 1);
bits.Add(((b & 0x3) >> 1) == 1);
bits.Add((b & 0x1) == 1);
}
BoolArray ba = new BoolArray(bits.ToArray());
return ba;
}
public string ToHexString(string bitSep8 = null, string bitSep128 = null)
{
string s = string.Empty;
int b = 0;
bool[] bbits = this.ToArray();
for (int i = 1; i <= bbits.Length; i++)
{
b = (b << 1) | (bbits[i - 1] ? 1 : 0);
if (i % 4 == 0)
{
s = s + string.Format("{0:x}", b);
b = 0;
}
if (i % (8 * 16) == 0)
{
s = s + bitSep128;
}
else if (i % 8 == 0)
{
s = s + bitSep8;
}
}
int ebits = bbits.Length % 4;
if (ebits != 0)
{
b = b << (4 - ebits);
s = s + string.Format("{0:x}", b);
}
return s;
}
public static BoolArray FromBinaryString(string bin, char[] trueChars = null)
{
if (trueChars == null) trueChars = new char[] { '1', 'Y', 'y', 'T', 't' };
if (bin == null) throw new ArgumentNullException("bin");
BoolArray ba = new BoolArray(bin.Length);
for (int i = 0; i < bin.Length; i++) ba[i] = bin[i].In(trueChars);
return ba;
}
public string ToBinaryString(char setChar = '1', char unsetChar = '0')
{
return new string(this.ToArray().Select(v => v ? setChar : unsetChar).ToArray());
}
#endregion
#region Class Methods
public bool[] ToArray()
{
bool[] vbits = new bool[this._length];
for (int i = 0; i < _length; i++) vbits[i] = this[i];
return vbits;
}
public BoolArray Append(ICollection<bool> addBits)
{
int startPos = this._length;
Extend(addBits.Count);
bool[] bitArray = addBits.ToArray();
for (int i = 0; i < bitArray.Length; i++) this[i + startPos] = bitArray[i];
return this;
}
public BoolArray Append(BoolArray addBits)
{
return this.Append(addBits.ToArray());
}
public static BoolArray Concatenate(params BoolArray[] bArrays)
{
return new BoolArray(bArrays.SelectMany(ba => ba.ToArray()).ToArray());
}
private void Extend(int numBits)
{
numBits += this._length;
int reqBytes = RequiredSize(numBits);
if (reqBytes > this.bits.Length)
{
UInt32[] newBits = new UInt32[reqBytes];
this.bits.CopyTo(newBits, 0);
this.bits = newBits;
}
this._length = numBits;
}
public bool Get(int index)
{
return this[index];
}
public BoolArray GetBits(int startBit = 0, int numBits = -1)
{
if (numBits == -1) numBits = bits.Length;
return new BoolArray(this.ToArray().Skip(startBit).Take(numBits).ToArray());
}
public BoolArray Repeat(int numReps)
{
bool[] oBits = this.ToArray();
List<bool> nBits = new List<bool>();
for(int i=0; i<numReps; i++) nBits.AddRange(oBits);
this.InitializeFrom(nBits);
return this;
}
public BoolArray Reverse()
{
int n = this.Count;
for(int i=0; i<n/2; i++)
{
bool b1 = this[i];
this[i] = this[n - i - 1];
this[n - i - 1] = b1;
}
return this;
}
public BoolArray Set(int index, bool v)
{
this[index] = v;
return this;
}
public BoolArray SetAll(bool v)
{
for (int i = 0; i < this.Count; i++) this[i] = v;
return this;
}
public BoolArray SetBits(ICollection<bool> setBits, int destStartBit = 0, int srcStartBit = 0, int numBits = -1, bool allowExtend = false)
{
if (setBits == null) throw new ArgumentNullException("setBits");
if ((destStartBit < 0) || (destStartBit >= this.Count)) throw new ArgumentOutOfRangeException("destStartBit");
if ((srcStartBit < 0) || (srcStartBit >= setBits.Count)) throw new ArgumentOutOfRangeException("srcStartBit");
bool[] sBits;
if (setBits is bool[]) sBits = (bool[])setBits;
else sBits = setBits.ToArray();
if (numBits == -1) numBits = setBits.Count;
if (numBits > (setBits.Count - srcStartBit)) numBits = setBits.Count - srcStartBit;
int diffSize = numBits - (this.Count - destStartBit);
if (diffSize > 0)
{
if (allowExtend) Extend(diffSize);
else numBits = this.Count - destStartBit;
}
for (int i = 0; i < numBits; i++) this[destStartBit + i] = sBits[srcStartBit + i];
return this;
}
public List<BoolArray> SplitEvery(int numBits)
{
int i = 0;
List<BoolArray> bitSplits = new List<BoolArray>();
while (i < this.Count)
{
bitSplits.Add(this.GetBits(i, numBits));
i += numBits;
}
return bitSplits;
}
public byte[] ToBytes(int startBit = 0, int numBits = -1)
{
if (numBits == -1) numBits = this._length - startBit;
BoolArray ba = GetBits(startBit, numBits);
int nb = (numBits + 7) / 8;
byte[] bb = new byte[nb];
for (int i = 0; i < ba.Count; i++)
{
if (!ba[i]) continue;
int bp = 7 - (i % 8);
bb[i / 8] = (byte)((int)bb[i / 8] | (1 << bp));
}
return bb;
}
#endregion
#region Logical Bitwise Operations
public BoolArray BinaryBitwiseOp(Func<bool, bool, bool> op, BoolArray ba, int start = 0)
{
for (int i = 0; i < ba.Count; i++)
{
if (start + i >= this.Count) break;
this[start + i] = op(this[start + i], ba[i]);
}
return this;
}
public BoolArray Xor(BoolArray xor, int start = 0)
{
return BinaryBitwiseOp((a, b) => (a ^ b), xor, start);
}
public BoolArray And(BoolArray and, int start = 0)
{
return BinaryBitwiseOp((a, b) => (a & b), and, start);
}
public BoolArray Or(BoolArray or, int start = 0)
{
return BinaryBitwiseOp((a, b) => (a | b), or, start);
}
public BoolArray Not(int start = 0, int len = -1)
{
for (int i = start; i < this.Count; i++)
{
if (--len == -1) break;
this[i] = !this[i];
}
return this;
}
#endregion
#region Class Operators
public static BoolArray operator +(BoolArray a, BoolArray b)
{
return a.Dup().Append(b);
}
public static BoolArray operator |(BoolArray a, BoolArray b)
{
return a.Dup().Or(b);
}
public static BoolArray operator &(BoolArray a, BoolArray b)
{
return a.Dup().And(b);
}
public static BoolArray operator ^(BoolArray a, BoolArray b)
{
return a.Dup().Xor(b);
}
public static BoolArray operator ~(BoolArray a)
{
return a.Dup().Not();
}
public static BoolArray operator <<(BoolArray a, int shift)
{
return a.Dup().Append(new bool[shift]);
}
public static BoolArray operator >>(BoolArray a, int shift)
{
return new BoolArray(a.ToArray().Take(Math.Max(0, a.Count - shift)).ToArray());
}
public static bool operator ==(BoolArray a, BoolArray b)
{
if (a.Count != b.Count) return false;
for (int i = 0; i < a.Count; i++) if (a[i] != b[i]) return false;
return true;
}
public override bool Equals(object obj)
{
if (!(obj is BoolArray)) return false;
return (this == (BoolArray)obj);
}
public override int GetHashCode()
{
return this.ToHexString().GetHashCode();
}
public static bool operator !=(BoolArray a, BoolArray b)
{
return !(a == b);
}
#endregion
}
}
I had the same issue, but had more than just the one Cardinality method to convert. So, I opted to port the entire BitSet class. Fortunately it was self-contained.
Here is the Gist of the C# port.
I have also added it to the open source BoboBrowse.Net project.
I have also ported the version from Apache Harmony (which is essentially a carbon copy of the JDK) and added it to the general library J2N so it is easy to consume.
Related
Hello I trying to do a QuickSort but didn't appear the result, For example the user input "cdabe" so the expected result is "abcde". May I know what is the cause why the result didn't display?
because There is no error in the code. I'm using MVC. My MergeSort is working properly but my QuickSort didn't.
Model :
public string QuickSort()
{
string arrangedSort = "";
string Word= "cdabe";
List<string> ListLetters = new List<string>();
for (int i = 0; i < Word.Length; i++)
{
ListLetters.Add(Word.Substring(i, 1));
}
aQuicksort(Word, 0, ListLetters.Count - 1);
void aQuicksort(string Word, int left, int right)
{
int i = left;
int j = right;
var pivot = Word[(left + right) / 2];
while (i <= j)
{
while (char.Parse(ListLetters[i]) < pivot)
i++;
while (char.Parse(ListLetters[i]) > pivot)
j--;
if (i <= j)
{
var tmp = ListLetters[i];
ListLetters[i] = ListLetters[j];
ListLetters[j] = tmp;
i++;
j--;
}
}
if (left < j)
aQuicksort(Word, left, j);
if (i < right)
aQuicksort(Word, i, right);
foreach (var listLetter in ListLetters)
{
arrangedSort += listLetter;
}
}
return arrangedSort;
}
Try this implementation, it uses LinQ using System.linq
public static IEnumerable<int> QSort3(IEnumerable<int> source)
{
if (!source.Any())
return source;
int first = source.First();
QSort3Helper myHelper =
source.GroupBy(i => i.CompareTo(first))
.Aggregate(new QSort3Helper(), (a, g) =>
{
if (g.Key == 0)
a.Same = g;
else if (g.Key == -1)
a.Less = g;
else if (g.Key == 1)
a.More = g;
return a;
});
IEnumerable<int> myResult = Enumerable.Empty<int>();
if (myHelper.Less != null)
myResult = myResult.Concat(QSort3(myHelper.Less));
if (myHelper.Same != null)
myResult = myResult.Concat(myHelper.Same);
if (myHelper.More != null)
myResult = myResult.Concat(QSort3(myHelper.More));
return myResult;
}
public class QSort3Helper
{
public IEnumerable<int> Less;
public IEnumerable<int> Same;
public IEnumerable<int> More;
}
code from this post
I'm trying to compile the below code: (normally get and set operation)
please assist with reviewing the insertion sort function, all the rest compiling perfectly.
The return value comparing 2 cells only (and it's correct).
any idea what can cause that?
private static void Main()
{
IArray<int?> arr = Read();
Console.WriteLine(arr);
SelectionSort(arr);
Console.WriteLine(arr);
if (arr.Length >= 2)
{
arr.Set(arr.Length - 2, null);
Console.WriteLine(arr);
}
if (arr.Length >= 1)
{
arr.Set(arr.Length - 1, null);
Console.WriteLine(arr);
}
SelectionSort(arr);
Console.WriteLine(arr);
Console.WriteLine("(" + arr.Get(100) + ")");
Console.WriteLine("insertion sort");
int n = arr.Length;
Insertionsort(arr, n);
Console.WriteLine(arr);
//// throw exception
//_ = new DynArr<int>();
}
private static IArray<int?> Read()
{
var arr = new DynArr<int?>();
Console.Write("Enter size >> ");
var size = int.Parse(Console.ReadLine().Trim());
for (var i = 0; i < size; ++i)
{
Console.Write("Enter [" + i + "] >> ");
arr.Set(i, int.Parse(Console.ReadLine().Trim()));
}
return arr;
}
}
private static void Insertionsort(IArray<int?> arr, int n)
{
for (int i = 1; i < n; i++)
{
var j = i - 1;
voidcompare(arr, i, j);
}
}
private static void voidcompare(IArray<int?> arr, int i, int j)
{
var c = arr.Get(i);
while (j >= 0 && arr.Get(j) > c)
{
arr.Set(j + 1, c);
}
}
}
}
Your Sort alg. isn't corect. See hier how it's working - Insertion Sort. Bellow i provide you a possible implementation.
public class Program
{
static void Main()
{
var collection = new List<int?> { 25, 71, 43, -1, 15, 0, 38 };
DoInsertionSort(collection, collection.Count);
Console.WriteLine(string.Join(Environment.NewLine, collection));
}
static void DoInsertionSort(IList<int?> collection, int length)
{
if (collection is null || collection.Count == 0 || length <= 0 || length > collection.Count)
{
return;
}
var previous = default(int?);
for (int index = 0; index < length; index++)
{
var current = collection.Get(index);
if (current < previous)
{
SwapUpToStart(collection, current, index);
}
previous = collection.Get(index);
}
}
private static void SwapUpToStart(IList<int?> collection, int? current, int currentIndex)
{
for (int index = currentIndex - 1; index >= 0; index--)
{
var previous = collection.Get(index);
if (current >= previous)
{
break;
}
collection.Swap(index, current, previous);
}
}
}
public static class YourIArray_T_Implementation
{
public static int? Get(this IList<int?> collection, int index)
{
return collection[index];
}
public static void Swap(this IList<int?> collection, int index, int? current, int? previous)
{
collection[index] = current;
collection[index + 1] = previous;
}
}
I'm having a problem with sorting and IComparer(). My program stops on it. I'm a beginner with C#.
Here is the part of the code where it stops:
public ArrayList ModelSort()
{
IComparer sorter = new R2SortHelper();
InnerList.Sort(sorter);
return InnerList;
}
private class R2SortHelper : System.Collections.IComparer
{
public int Compare(object x, object y)
{
double m1 = ((Model)x).R2() + ((Model)x).Valid().GetHashCode();
double m2 = ((Model)y).R2() + ((Model)y).Valid().GetHashCode();
if (m1 > m2)
return -1;
else if (m1 < m2)
return 1;
else
return 0;
}
}
Here is an error from console:
Unable to sort because the IComparer.Compare() method returns inconsistent results. Either a value does not compare equal to itself, or one value repeatedly compared to another value yields different results. IComparer: 'AMO.EnPI.AddIn.Utilities.ModelCollection+R2SortHelper'.
List of exceptions:
Exception Text
System.ArgumentException: Unable to sort because the IComparer.Compare() method returns inconsistent results. Either a value does not compare equal to itself, or one value repeatedly compared to another value yields different results. IComparer: 'AMO.EnPI.AddIn.Utilities.ModelCollection+R2SortHelper'.
at System.Array.SorterObjectArray.DepthLimitedQuickSort(Int32 left, Int32 right, Int32 depthLimit)
at System.Array.SorterObjectArray.DepthLimitedQuickSort(Int32 left, Int32 right, Int32 depthLimit)
at System.Array.Sort(Array keys, Array items, Int32 index, Int32 length, IComparer comparer)
at System.Collections.ArrayList.Sort(Int32 index, Int32 count, IComparer comparer)
at System.Collections.ArrayList.Sort(IComparer comparer)
at AMO.EnPI.AddIn.Utilities.ModelCollection.ModelSort() in C:\ENPI\EnPI\AMO.EnPI-5.0\AMO.EnPI.Utilities\Analytics.cs:line 961
at AMO.EnPI.AddIn.ModelSheet.WriteResultsTable(Int32 n, Boolean top) in C:\ENPI\EnPI\AMO.EnPI-5.0\AMO.EnPI.AddIn\ModelSheet.cs:line 146
at AMO.EnPI.AddIn.ModelSheet.Populate() in C:\ENPI\EnPI\AMO.EnPI-5.0\AMO.EnPI.AddIn\ModelSheet.cs:line 60
at AMO.EnPI.AddIn.ThisAddIn.plotEnPI(ListObject LO) in C:\ENPI\EnPI\AMO.EnPI-5.0\AMO.EnPI.AddIn\ThisAddIn.cs:line 318
at AMO.EnPI.AddIn.RegressionControl.runFunction(Object sender, EventArgs e) in C:\ENPI\EnPI\AMO.EnPI-5.0\AMO.EnPI.AddIn\RegressionControl.cs:line 817
at AMO.EnPI.AddIn.CO2EmissionControl.btnCalculate_Click(Object sender, EventArgs e) in C:\ENPI\EnPI\AMO.EnPI-5.0\AMO.EnPI.AddIn\CO2EmissionControl.cs:line 148
My model class:
public class Model
{
public int ModelNumber { get; set; }
public double[] Ys { get; set; }
public double[,] Xs { get; set; }
public string[] VariableNames { get; set; }
public double RMSError { get; set; }
public double[] Coefficients { get; set; }
public Model()
{
ModelNumber = 0;
Ys = null;
Xs = null;
VariableNames = null;
RMSError = 0;
Coefficients = null;
}
public Model(int ModelNumber, double[] Ys, double[,] Xs, string[] VariableNames)
{
RMSError = 0;
Coefficients = null;
// run LLS
int info;
double[] c;
alglib.lsfitreport rep;
try
{
alglib.lsfitlinear(Ys, Xsplusone(), out info, out c, out rep);
}
catch
{
throw;
}
Coefficients = c;
RMSError = rep.rmserror;
}
public void Run() //double[] Ys, double[,] Xs, string[] VariableNames)
{
RMSError = 0;
Coefficients = null;
if (Ys != null && Xs != null)
{
// run LLS
int info;
double[] c;
alglib.lsfitreport rep;
try
{
alglib.lsfitlinear(Ys, Xsplusone(), out info, out c, out rep);
}
catch
{
throw;
}
Coefficients = c;
RMSError = rep.rmserror;
}
}
public int N()
{
return Ys.Count();
}
public int df()
{
return N() - k() - 1;
}
public int k()
{
return VariableNames.Count();
}
public double TotalSS()
{
// compute total sum of squares
double ybar = Ys.Average();
double sst = 0;
for (int i = Ys.GetLowerBound(0); i <= Ys.GetUpperBound(0); i++)
{
sst += Math.Pow(Ys[i] - ybar, 2);
}
return sst;
}
public double ResidualSS ()
{
return ( N() * Math.Pow( RMSError, 2));
}
public double R2()
{
return (1 - (ResidualSS() / TotalSS()));
}
public double AdjustedR2()
{
return (1 - (((1 - R2()) * (N() - 1)) / (N() - k() - 1)));
}
public double F()
{
return ( (R2() / k()) / ((1 - R2()) / (N() - k() - 1)));
}
public double ModelPValue()
{
double modelP = 0;
double modelF = F();
if (modelF < 0) modelF = 0;
try
{
modelP = alglib.fcdistribution(N() - df() - 1, df(), modelF);
}
catch (alglib.alglibexception e)
{
}
return modelP;
}
public bool Valid()
{
// Model validity criteria, from the SEP M&V protocol:
// The model p-value must be less than 0.1
// All variables must have p-values less than 0.2
// At least one variable must have a p-value of less than 0.1
// The R2 value must be greater than 0.5
double[] ps = PValues();
bool varsvalid = true;
bool varlowexists = false;
for (int i = 0; i < ps.Count(); i++)
{
if (ps[i] <= Constants.PVALUE_THRESHOLD)
varlowexists = true;
if (ps[i] > Constants.PVALUE_HIGH)
varsvalid = false;
}
if (!varlowexists)
return false;
if (!varsvalid)
return false;
if (ModelPValue() > Constants.PVALUE_THRESHOLD)
return false;
if (R2() < Constants.R2VALUE_MIN)
return false;
return true;
}
public string Formula()
{
string formula = "";
int offset = Coefficients.GetLowerBound(0) - VariableNames.GetLowerBound(0);
for (int i = Coefficients.GetLowerBound(0); i < Coefficients.GetUpperBound(0); i++)
{
formula += "(" + Coefficients[i].ToString("0.0000") + " * " + ExcelHelpers.CreateValidFormulaName(VariableNames[i - offset]) + ") + ";
// formula += "(" + Coefficients[i].ToString() + " * " + ExcelHelpers.CreateValidFormulaName(VariableNames[i - offset]) + ") + ";
}
formula += Coefficients[Coefficients.GetUpperBound(0)].ToString("0.00");
return formula;
}
public double[,] Xsplusone()
{
return DataHelper.arrayAddIdentity(Xs, 0, 1); // add on a column of ones for the intercept
}
public double[] PredictedYs()
{ // compute the predicted ys
double[] yhat = new double[N()];
double[,] xs = Xsplusone();
double[] c = Coefficients;
for (int i = 0; i < N(); i++)
{
yhat[i] = 0;
for (int j = 0; j < k() + 1; j++)
{
yhat[i] += xs[i, j] * c[j];
}
}
return yhat;
}
public double[,] CovarianceMatrix()
{
// compute the coefficient covariance matrix
double[,] twodYs = DataHelper.dbl2DArray(Ys);
double[,] XYs = DataHelper.dblarrayUnion(Xs, twodYs);
double[,] cov;
int info;
alglib.linearmodel lm;
alglib.lrreport rpt;
try
{
alglib.lrbuild(XYs, N(), k(), out info, out lm, out rpt);
cov = rpt.c;
}
catch
{
throw;
}
return cov;
}
public double[] StandardErrors()
{
// compute the x std errors and p-values
double[,] cov = CovarianceMatrix();
double[] se = new double[k()];
if (cov.GetLength(0) > 0 && cov.GetLength(1) > 0)
{
for (int j = 0; j < k(); j++)
{
se[j] = Math.Sqrt(cov[j, j]);
}
}
return se;
}
public double[] PValues()
{
double[] c = Coefficients;
double[,] cov = CovarianceMatrix();
double[] se = StandardErrors();
double[] pv = new double[k()];
if (cov.GetLength(0) > 0 && cov.GetLength(1) > 0)
{
for (int j = 0; j < k(); j++)
{
se[j] = Math.Sqrt(cov[j, j]);
try
{
pv[j] = 2 * (1 - alglib.studenttdistribution(df(), Math.Abs(c[j] / se[j])));
}
catch
{
}
}
}
return pv;
}
public string AICFormula()
{
return "";
}
//Added By Suman for SEP Validation changes
public string[] SEPValidationCheck()
{
string[] sepChk = new string[k()];
for (int cnt = 0; cnt < sepChk.Length; cnt++)
{
if (Valid() == true)
{
sepChk[cnt] = "Pass";
}
else
{
sepChk[cnt] = "Fail";
}
}
return sepChk;
}
}
Here is GetHashCode():
public override int GetHashCode()
{
return x.GetHashCode() ^ y.GetHashCode();
}
My R2():
public double R2()
{
return (1 - (ResidualSS() / TotalSS()));
}
For the majority of types, you can't sort by GetHashCode() since the hash code calculations aren't necessarily going to sort in the same order as the value. You can only sort on GetHashCode() reliably when it is the value itself (such as int), but at that point there isn't any point in getting the hash code since you already have the value. Also you didn't show what R2() and Valid() methods do, so who knows what kind of unholyness is going on in there.
EDIT (OP updated code):
Your GetHashCode() usage is definitely not sortable. Nor is adding a boolean to a double. 5 + 0 vs. 2 + 1 is not going to sort correctly (assuming you want the falses up front?)
Just use ((Model)x).R2() vs ((Model)y).R2() as the comparison, if you want the falses or trues up front, you can add something like:
if (x.Valid && !y.Valid)
return 1;
if (!x.Valid && y.Valid)
return -1;
//then do your R2 comparisons here.
That preamble will cause the non valids to always come first and then sort by R2s. You can reverse if you want to go the other way.
Your .Valid() method is returning boolean, and then you go to find hash code. Is this expected from your code?
Basically, you are doing some double value + boolean.GetHashCode(). Solution would be to not use .Valid() in your right side expression. Check that separately.
private class R2SortHelper : System.Collections.IComparer
{
public int Compare(object x, object y)
{
Model xModel = (Model)x;
Model yModel = (Model)y;
if((Model.Valid()==true) && (yModel.Valid()==true))
{
double m1 = xModel.R2() + xModel.GetHashCode();
double m2 = yModel.R2() + yModel.GetHashCode();
return (m1 > m2) ? -1 : ((m1 < m2) ? 1 :0);
}
return 0;
}
}
I am using this linq query to sort a string column but the results I am getting does not seems to be in right order?
Query:
userList = users.OrderBy(u => u.FirstName)
.Skip(offset)
.Take(rowcount)
.ToList<User>();
Result:
rama &
11Rama
15rama
1Rama
2Rama
490110rama
IU-Rama
Rama
it should be something like?
1Rama
2Rama
11Rama
15rama
490110rama
IU-Rama
rama &
Rama
You are getting your result sorted by the code points of the characters and that is by far the most common implementation for sorting strings. What you are expecting is called natural sort order, see for example this article, but you will have to do it on your own because .NET does not provide this out of the box.
By adding this code you will be able to sort as you need it to be done. But this sorting will be done on client side and all records must be fetch as list.
userList = users.ToList<User>()
.OrderBy(u => u.FirstName,new NumericComparer())
.Skip(offset)
.Take(rowcount)
.ToList<User>();
public class NumericComparer : IComparer<string>
{
public int Compare(string x, string y)
{
return StringLogicalComparer.Compare(x, y);
}
}
public class StringLogicalComparer
{
public static int Compare(string s1, string s2)
{
//get rid of special cases
if ((s1 == null) && (s2 == null)) return 0;
if (s1 == null) return -1;
if (s2 == null) return 1;
if ((s1.Equals(string.Empty) && (s2.Equals(string.Empty)))) return 0;
if (s1.Equals(string.Empty)) return -1;
if (s2.Equals(string.Empty)) return -1;
//WE style, special case
bool sp1 = Char.IsLetterOrDigit(s1, 0);
bool sp2 = Char.IsLetterOrDigit(s2, 0);
if (sp1 && !sp2) return 1;
if (!sp1 && sp2) return -1;
int i1 = 0, i2 = 0; //current index
while (true)
{
bool c1 = Char.IsDigit(s1, i1);
bool c2 = Char.IsDigit(s2, i2);
int r; // temp result
if (!c1 && !c2)
{
bool letter1 = Char.IsLetter(s1, i1);
bool letter2 = Char.IsLetter(s2, i2);
if ((letter1 && letter2) || (!letter1 && !letter2))
{
r = letter1 ? Char.ToLower(s1[i1]).CompareTo(Char.ToLower(s2[i2])) : s1[i1].CompareTo(s2[i2]);
if (r != 0) return r;
}
else if (!letter1) return -1;
else return 1;
}
else if (c1 && c2)
{
r = CompareNum(s1, ref i1, s2, ref i2);
if (r != 0) return r;
}
else if (c1)
{
return -1;
}
else
{
return 1;
}
i1++;
i2++;
if ((i1 >= s1.Length) && (i2 >= s2.Length))
{
return 0;
}
if (i1 >= s1.Length)
{
return -1;
}
if (i2 >= s2.Length)
{
return -1;
}
}
}
private static int CompareNum(string s1, ref int i1, string s2, ref int i2)
{
int nzStart1 = i1, nzStart2 = i2; // nz = non zero
int end1 = i1, end2 = i2;
ScanNumEnd(s1, i1, ref end1, ref nzStart1);
ScanNumEnd(s2, i2, ref end2, ref nzStart2);
int start1 = i1; i1 = end1 - 1;
int start2 = i2; i2 = end2 - 1;
int nzLength1 = end1 - nzStart1;
int nzLength2 = end2 - nzStart2;
if (nzLength1 < nzLength2) return -1;
if (nzLength1 > nzLength2) return 1;
for (int j1 = nzStart1, j2 = nzStart2; j1 <= i1; j1++, j2++)
{
int r = s1[j1].CompareTo(s2[j2]);
if (r != 0) return r;
}
// the nz parts are equal
int length1 = end1 - start1;
int length2 = end2 - start2;
if (length1 == length2) return 0;
if (length1 > length2) return -1;
return 1;
}
private static void ScanNumEnd(string s, int start, ref int end, ref int nzStart)
{
nzStart = start;
end = start;
bool countZeros = true;
while (Char.IsDigit(s, end))
{
if (countZeros && s[end].Equals('0'))
{
nzStart++;
}
else countZeros = false;
end++;
if (end >= s.Length) break;
}
}
}
Creating a custom IComparer would work for you.
Check this implementation: http://zootfroot.blogspot.com/2009/09/natural-sort-compare-with-linq-orderby.html
You code would then call myLinqQuery.OrderBy(item => item.sortProperty, new MyComparer<string>())
In his example, the sort order return:
image1.jpg
image4.jpg
image30.jpg
image200.jpg
I'm working on a bit-based B/W/Greyscale Pre-Compiled font format, and was having issues with either reading or writing the format, (I've not been able to determine where the issue was. (I do have a B/W bit-based version working, but an Aliased font doesn't look too good, as you can imagine, especially when working with a 320x200 pixel screen) ) but decided that just using a BinaryWriter would be much easier than writing to a bool[] when I pulled the image data.
The basic format of a pixel in the file looks like this:
1 - White Pixel (Shortest, as this would be most of the pixels)
00 - Black Pixel (No reason to write 10-bits for a pure black pixel, which there are a reasonable number of)
01 - Greyscale Pixel, and is followed by 1 byte describing the shade of the pixel
Now, everything is fine and dandy with writing the required info, as that's all full bytes, but the default .Net 4.0 BinaryWriter writes a Boolean value as a full byte, and as you can imagine, that negates the use of a bit-based format. So I was wondering, is there a BinaryWriter, (and BinaryReader) implementation out there that's bit-based
Edit:
I ended up creating my own. (See the answer for the code.)
I ended up writing my own, so here they are.
The BinaryWriter (I've only overridden the ones that I needed)
private class BinaryWriter : System.IO.BinaryWriter
{
private bool[] curByte = new bool[8];
private byte curBitIndx = 0;
private System.Collections.BitArray ba;
public BinaryWriter(Stream s) : base(s) { }
public override void Flush()
{
base.Write(ConvertToByte(curByte));
base.Flush();
}
public override void Write(bool value)
{
curByte[curBitIndx] = value;
curBitIndx++;
if (curBitIndx == 8)
{
base.Write(ConvertToByte(curByte));
this.curBitIndx = 0;
this.curByte = new bool[8];
}
}
public override void Write(byte value)
{
ba = new BitArray(new byte[] { value });
for (byte i = 0; i < 8; i++)
{
this.Write(ba[i]);
}
ba = null;
}
public override void Write(byte[] buffer)
{
for (int i = 0; i < buffer.Length; i++)
{
this.Write((byte)buffer[i]);
}
}
public override void Write(uint value)
{
ba = new BitArray(BitConverter.GetBytes(value));
for (byte i = 0; i < 32; i++)
{
this.Write(ba[i]);
}
ba = null;
}
public override void Write(ulong value)
{
ba = new BitArray(BitConverter.GetBytes(value));
for (byte i = 0; i < 64; i++)
{
this.Write(ba[i]);
}
ba = null;
}
public override void Write(ushort value)
{
ba = new BitArray(BitConverter.GetBytes(value));
for (byte i = 0; i < 16; i++)
{
this.Write(ba[i]);
}
ba = null;
}
private static byte ConvertToByte(bool[] bools)
{
byte b = 0;
byte bitIndex = 0;
for (int i = 0; i < 8; i++)
{
if (bools[i])
{
b |= (byte)(((byte)1) << bitIndex);
}
bitIndex++;
}
return b;
}
}
And, the BinaryReader, once again, I've only overridden the methods that I needed.
private class BinaryReader : System.IO.BinaryReader
{
private bool[] curByte = new bool[8];
private byte curBitIndx = 0;
private BitArray ba;
public BinaryReader(Stream s) : base(s)
{
ba = new BitArray(new byte[] { base.ReadByte() });
ba.CopyTo(curByte, 0);
ba = null;
}
public override bool ReadBoolean()
{
if (curBitIndx == 8)
{
ba = new BitArray(new byte[] { base.ReadByte() });
ba.CopyTo(curByte, 0);
ba = null;
this.curBitIndx = 0;
}
bool b = curByte[curBitIndx];
curBitIndx++;
return b;
}
public override byte ReadByte()
{
bool[] bar = new bool[8];
byte i;
for (i = 0; i < 8; i++)
{
bar[i] = this.ReadBoolean();
}
byte b = 0;
byte bitIndex = 0;
for (i = 0; i < 8; i++)
{
if (bar[i])
{
b |= (byte)(((byte)1) << bitIndex);
}
bitIndex++;
}
return b;
}
public override byte[] ReadBytes(int count)
{
byte[] bytes = new byte[count];
for (int i = 0; i < count; i++)
{
bytes[i] = this.ReadByte();
}
return bytes;
}
public override ushort ReadUInt16()
{
byte[] bytes = ReadBytes(2);
return BitConverter.ToUInt16(bytes, 0);
}
public override uint ReadUInt32()
{
byte[] bytes = ReadBytes(4);
return BitConverter.ToUInt32(bytes, 0);
}
public override ulong ReadUInt64()
{
byte[] bytes = ReadBytes(8);
return BitConverter.ToUInt64(bytes, 0);
}
}
I don't believe there's anything in the framework for this, no. Basically you'd need to write a class to wrap a BinaryWriter (or just a stream) and "the byte written so far" and the number of bits written. When the number of bits gets to 8, write the byte to the underlying stream and clear.
EDIT: the OP posted a possible and working implementation of the above suggestion below.
If you keep your data in a byte array (bools are of no use and take too much space, if you use them for bits, they take up a byte in memory) or in an array of a particular struct that fits your dataformat.
Once you have an internal memory representation, you don't need a bit-based binary writer anymore. You can simply write the data to a BinaryWriter and you're done with it.
...but the default .Net 4.0 BinaryWriter writes a Boolean value as a full
byte, and as you can imagine, that negates the use of a bit-based
format....
The reason for this is: the bool is, by definition, of 1 byte size in C#. The BinaryWriter simply writes what you give it.
I found myself in need of this as well, so I built upon OP and filled in all the read/writes (except char & string since those are a bit special).
I also made a quick unit test try it out. For streams containing only boolean (or other custom sub-byte value types) it's obviously 87.5% cheaper, and for a random mixed stream containing 75% boolean values, it was about 33% cheaper. So could be useful for some scenarios.
Here are the both classes in case anyone else needs them, use at your own risk:
/// <summary>
/// A binary writer that packs data into bits, to preserve space when using many bit/boolean values. Up to about 87.5% cheaper for streams that only contains boolean values.
/// By: jsmars#gmail.com, based on posters classes in this post: https://stackoverflow.com/questions/7051939/bit-based-binarywriter-in-c-sharp
/// </summary>
public class BinaryBitWriter : BinaryWriter
{
public byte BitPosition { get; private set; } = 0;
private bool[] curByte = new bool[8];
private System.Collections.BitArray ba;
public BinaryBitWriter(Stream s) : base(s) { }
public override void Flush()
{
flushBitBuffer();
base.Flush();
}
public override void Write(byte[] buffer, int index, int count)
{
for (int i = index; i < index + count; i++)
Write((byte)buffer[i]);
}
public override void Write(byte value)
{
ba = new BitArray(new byte[] { value });
for (byte i = 0; i < 8; i++)
Write(ba[i]);
}
public override void Write(bool value)
{
curByte[BitPosition] = value;
BitPosition++;
if (BitPosition == 8)
flushBitBuffer();
}
public override void Write(char[] chars, int index, int count)
{
for (int i = index; i < index + count; i++)
Write(chars[i]);
}
public override void Write(string value)
{
// write strings as normal for now, so flush the bits first
flushBitBuffer();
base.Write(value);
}
public override void Write(decimal value)
{
var ints = decimal.GetBits(value);
for (int i = 0; i < ints.Length; i++)
Write(ints[i]);
}
public override void Write(float value) => Write(BitConverter.GetBytes(value));
public override void Write(ulong value) => Write(BitConverter.GetBytes(value));
public override void Write(long value) => Write(BitConverter.GetBytes(value));
public override void Write(uint value) => Write(BitConverter.GetBytes(value));
public override void Write(int value) => Write(BitConverter.GetBytes(value));
public override void Write(ushort value) => Write(BitConverter.GetBytes(value));
public override void Write(short value) => Write(BitConverter.GetBytes(value));
public override void Write(double value) => Write(BitConverter.GetBytes(value));
public override void Write(char[] value) => Write(value, 0, value.Length);
public override void Write(char value)
{
// write strings as normal for now, so flush the bits first
flushBitBuffer();
base.Write(value);
//var b = BitConverter.GetBytes(value);
//Write(b);
}
public override void Write(byte[] buffer) => Write(buffer, 0, buffer.Length);
public override void Write(sbyte value) => Write((byte)value);
void flushBitBuffer()
{
if (BitPosition == 0) // Nothing to flush
return;
base.Write(ConvertToByte(curByte));
BitPosition = 0;
curByte = new bool[8];
}
private static byte ConvertToByte(bool[] bools)
{
byte b = 0;
byte bitIndex = 0;
for (int i = 0; i < 8; i++)
{
if (bools[i])
b |= (byte)(((byte)1) << bitIndex);
bitIndex++;
}
return b;
}
}
public class BinaryBitReader : BinaryReader
{
public byte BitPosition { get; private set; } = 8;
private bool[] curByte = new bool[8];
public BinaryBitReader(Stream s) : base(s)
{
}
public override bool ReadBoolean()
{
if (BitPosition == 8)
{
var ba = new BitArray(new byte[] { base.ReadByte() });
ba.CopyTo(curByte, 0);
BitPosition = 0;
}
bool b = curByte[BitPosition];
BitPosition++;
return b;
}
public override byte ReadByte()
{
bool[] bar = new bool[8];
byte i;
for (i = 0; i < 8; i++)
{
bar[i] = this.ReadBoolean();
}
byte b = 0;
byte bitIndex = 0;
for (i = 0; i < 8; i++)
{
if (bar[i])
{
b |= (byte)(((byte)1) << bitIndex);
}
bitIndex++;
}
return b;
}
public override byte[] ReadBytes(int count)
{
byte[] bytes = new byte[count];
for (int i = 0; i < count; i++)
{
bytes[i] = this.ReadByte();
}
return bytes;
}
//public override int Read() => BitConverter.ToUInt64(ReadBytes(8), 0);
public override int Read(byte[] buffer, int index, int count)
{
for (int i = index; i < index + count; i++)
buffer[i] = ReadByte();
return count; // we can return this here, it will die at the above row if anything is off
}
public override int Read(char[] buffer, int index, int count)
{
for (int i = index; i < index + count; i++)
buffer[i] = ReadChar();
return count; // we can return this here, it will die at the above row if anything is off
}
public override char ReadChar()
{
BitPosition = 8;
return base.ReadChar();
//BitConverter.ToChar(ReadBytes(2), 0);
}
public override char[] ReadChars(int count)
{
var chars = new char[count];
Read(chars, 0, count);
return chars;
}
public override decimal ReadDecimal()
{
int[] ints = new int[4];
for (int i = 0; i < ints.Length; i++)
ints[i] = ReadInt32();
return new decimal(ints);
}
public override double ReadDouble() => BitConverter.ToDouble(ReadBytes(8), 0);
public override short ReadInt16() => BitConverter.ToInt16(ReadBytes(2), 0);
public override int ReadInt32() => BitConverter.ToInt32(ReadBytes(4), 0);
public override long ReadInt64() => BitConverter.ToInt64(ReadBytes(8), 0);
public override sbyte ReadSByte() => (sbyte)ReadByte();
public override float ReadSingle() => BitConverter.ToSingle(ReadBytes(4), 0);
public override string ReadString()
{
BitPosition = 8; // Make sure we read a new byte when we start reading the string
return base.ReadString();
}
public override ushort ReadUInt16() => BitConverter.ToUInt16(ReadBytes(2), 0);
public override uint ReadUInt32() => BitConverter.ToUInt32(ReadBytes(4), 0);
public override ulong ReadUInt64() => BitConverter.ToUInt64(ReadBytes(8), 0);
}
And the unit tests:
public static bool UnitTest()
{
const int testPairs = 512;
var bitstream = new MemoryStream();
var bitwriter = new BinaryBitWriter(bitstream);
var bitreader = new BinaryBitReader(bitstream);
byte[] bytes = new byte[] { 1, 2, 3, 4, 255 };
byte Byte = 128;
bool Bool = true;
char[] chars = new char[] { 'a', 'b', 'c' };
string str = "hello";
var Float = 2.5f;
ulong Ulong = 12345678901234567890;
long Long = 1122334455667788;
uint Uint = 1234567890;
int Int = 999998888;
ushort UShort = 12345;
short Short = 4321;
double Double = 9.9;
char Char = 'A';
sbyte Sbyte = -128;
decimal Decimal = 10000.00001m;
List<BBTest> pairs = new List<BBTest>();
// Make pairs of write and read tests
pairs.Add(new BBTest(Bool, (w) => w.Write(Bool), (r) => { if (r.ReadBoolean() != Bool) throw new Exception(); }));
pairs.Add(new BBTest(bytes, (w) => w.Write(bytes, 0, 5), (r) => { if (arrayCompare(r.ReadBytes(5), bytes)) throw new Exception(); }));
pairs.Add(new BBTest(Byte, (w) => w.Write(Byte), (r) => { if (r.ReadByte() != Byte) throw new Exception(); }));
pairs.Add(new BBTest(chars, (w) => w.Write(chars, 0, 3), (r) => { if (arrayCompare(r.ReadChars(3), chars)) throw new Exception(); })); /////////////
pairs.Add(new BBTest(str, (w) => w.Write(str), (r) => { string s; if ((s = r.ReadString()) != str) throw new Exception(); }));
pairs.Add(new BBTest(Decimal, (w) => w.Write(Decimal), (r) => { if (r.ReadDecimal() != Decimal) throw new Exception(); }));
pairs.Add(new BBTest(Float, (w) => w.Write(Float), (r) => { if (r.ReadSingle() != Float) throw new Exception(); }));
pairs.Add(new BBTest(Ulong, (w) => w.Write(Ulong), (r) => { if (r.ReadUInt64() != Ulong) throw new Exception(); }));
pairs.Add(new BBTest(Long, (w) => w.Write(Long), (r) => { if (r.ReadInt64() != Long) throw new Exception(); }));
pairs.Add(new BBTest(Uint, (w) => w.Write(Uint), (r) => { if (r.ReadUInt32() != Uint) throw new Exception(); }));
pairs.Add(new BBTest(Int, (w) => w.Write(Int), (r) => { if (r.ReadInt32() != Int) throw new Exception(); }));
pairs.Add(new BBTest(UShort, (w) => w.Write(UShort), (r) => { if (r.ReadUInt16() != UShort) throw new Exception(); }));
pairs.Add(new BBTest(Short, (w) => w.Write(Short), (r) => { if (r.ReadInt16() != Short) throw new Exception(); }));
pairs.Add(new BBTest(Double, (w) => w.Write(Double), (r) => { if (r.ReadDouble() != Double) throw new Exception(); }));
pairs.Add(new BBTest(Char, (w) => w.Write(Char), (r) => { if (r.ReadChar() != Char) throw new Exception(); })); ///////////////
pairs.Add(new BBTest(bytes, (w) => w.Write(bytes), (r) => { if (arrayCompare(r.ReadBytes(5), bytes)) throw new Exception(); }));
pairs.Add(new BBTest(Sbyte, (w) => w.Write(Sbyte), (r) => { if (r.ReadSByte() != Sbyte) throw new Exception(); }));
// Now add all tests, and then a bunch of randomized tests, to make sure we test lots of combinations incase there is some offsetting error
List<BBTest> test = new List<BBTest>();
test.AddRange(pairs);
var rnd = new Random();
for (int i = 0; i < testPairs - test.Count; i++)
{
if (rnd.NextDouble() < 0.75)
test.Add(pairs[0]);
else
test.Add(pairs[rnd.Next(pairs.Count)]);
}
// now write all the tests
for (int i = 0; i < test.Count; i++)
test[i].Writer(bitwriter);
bitwriter.Flush();
// now reset the stream and test to see that they are the same
bitstream.Position = 0;
for (int i = 0; i < test.Count; i++)
test[i].ReadTest(bitreader);
// As comparison, lets write the same stuff to a normal binarywriter and compare sized
var binstream = new MemoryStream();
var binwriter = new BinaryWriter(binstream);
for (int i = 0; i < test.Count; i++)
test[i].Writer(binwriter);
binwriter.Flush();
var saved = 1 - bitstream.Length / (float)binstream.Length;
var result = $"BinaryBitWriter was {(saved * 100).ToString("0.00")}% cheaper than a normal BinaryWriter with random data";
bool arrayCompare(IEnumerable a, IEnumerable b)
{
var B = b.GetEnumerator();
B.MoveNext();
foreach (var item in a)
{
if (item != B.Current)
return false;
B.MoveNext();
}
return true;
}
return true;
}
delegate void writer(BinaryWriter w);
delegate void reader(BinaryReader r);
class BBTest
{
public object Object;
public writer Writer;
public reader ReadTest;
public BBTest(object obj, writer w, reader r) { Object = obj; Writer = w; ReadTest = r; }
public override string ToString() => Object.ToString();
}