Friday, March 31, 2017

Don't compare floats

Floating-point numbers are tricky; one of the first things a programmer needs to remember when working with them is to never check floats for equality. (I believe ReSharper warns you if you do that; I don't know if plain Visual Studio does because I never use it without ReSharper.)

If precise representations of decimal numbers is needed, like when manipulating currencies, use decimals instead (if using C#); if a similar primitive type does not exist in your language, write a separate package / module / library to "fake it" by using integer values and scale them down by two or four digits, depending on your needs. (For example, the number 123456 can represent either 1,234.56 or 12.3456, depending on your application.)

Here's a simple code example to show the difference between floats and decimals in C#:

float f1 = 0.1f;
float f2 = f1 * 10.0f;

float f3 = 0.0f;
for (var i = 1; i <= 10; i++)
    f3 += f1;

Console.WriteLine(f2 == f3);

decimal d1 = 0.1m;
decimal d2 = d1 * 10.0m;

decimal d3 = 0.0m;
for (var i = 1; i <= 10; i++)
    d3 += d1;

Console.WriteLine(d2 == d3);

Running this in LinqPad prints out:


(A peculiarity of the decimal type in C# is that it keeps track of the number of decimal places that have been used, hence the 1.00 vs 1.0 in the second part of the results.)

Wednesday, March 15, 2017

Evaluating an expression

Leaving a note to myself - a simple algorithm for evaluating expressions, no unary operators or parentheses.
phase 1 (tokenizer)

'+' => op1, add
'-' => op1, sub
'*' => op2, mul
'/' => op2, div
\d+ => number, value

phase 2 (evaluator)

tuple = first (number, op2, number)
while tuple:
  replace tuple with result of op2

tuple = first (number, op1, number)
while tuple:
  replace tuple with result of op1

there should be a single item left, a number; return its value

Saturday, June 25, 2016

Returning an IEnumerable from a database

This is probably rather obvious, but... when returning an `IEnumerable` from a database, like the records from a table, don't do this:

using (var db = GetDatabase())
  return db.GetTable("Table1");

because it will throw an exception when trying to enumerate those records, since the database connection has already been disposed.

Don't do this either:

using (var db = GetDatabase())
  return db.GetTable("Table1").ToList();

because it will retrieve all records from the table, even if you only need a small subset.

A slightly better way is to do this:

using (var db = GetDatabase())
  foreach (var item in db.GetTable("Table1"))
    yield return item;

This way, the `Dispose` method doesn't get called until the enumeration is over and if you only `Take()` a limited number of records from the result, it won't load the whole table. On the other hand, if you only add `Where()` clauses to the result, it will still enumerate everything (the "where" doesn't get passed on to the database engine).

This is not perfect - it would be best if I could return an IQueryable so that additional filters get passed on to the database engine, but I haven't yet figured out how to do that.