Warning: include() [function.include]: Unable to access /var/www/html/rogue-development/blog2/wp-content/advanced-cache.php in /var/www/html/rogue-development/blog2/wp-settings.php on line 62

Warning: include(/var/www/html/rogue-development/blog2/wp-content/advanced-cache.php) [function.include]: failed to open stream: No such file or directory in /var/www/html/rogue-development/blog2/wp-settings.php on line 62

Warning: include() [function.include]: Failed opening '/var/www/html/rogue-development/blog2/wp-content/advanced-cache.php' for inclusion (include_path='.:/usr/share/pear:/usr/share/php') in /var/www/html/rogue-development/blog2/wp-settings.php on line 62

Notice: add_option was called with an argument that is deprecated since version 2.3 with no alternative available. in /var/www/html/rogue-development/blog2/wp-includes/functions.php on line 3468

Notice: register_sidebar_widget is deprecated since version 2.8! Use wp_register_sidebar_widget() instead. in /var/www/html/rogue-development/blog2/wp-includes/functions.php on line 3382

Notice: register_widget_control is deprecated since version 2.8! Use wp_register_widget_control() instead. in /var/www/html/rogue-development/blog2/wp-includes/functions.php on line 3382
ruby « Marc’s Musings

Tag Archive for 'ruby'

Reminder: Floats are not precise

I was chatting with a couple friends the other day about an odd bug that was due to floating point precision.  Neither of them got it at first, and it reminded me that not everyone realizes how imprecise floating point math can be.  I know this, you know this, even the friends I was talking to knew it after they thought about it.  But it’s so easy to ignore it since floating point math usually does what we want.  Here’s three amazingly simple examples:

Actionscript:

  1. var val:Number = 0.0;
  2. for( var i:int = 0 ; i < 10 ; i++ )
  3. {
  4.         val += 0.1;
  5. }
  6. trace(val);

Java:

  1. public class FloatTest {
  2.         public static void main(String[] args) {
  3.                 float val = 0;
  4.                 for( int i = 0 ; i < 10 ; i++)
  5.                 {
  6.                         val += 0.1;
  7.                 }
  8.                 System.out.println( val );
  9.         }
  10. }

Ruby (I had to go a bit higher on the loop since it rounds differently):

  1. val = 0
  2. (1..100).each do
  3.   val += 0.1
  4. end
  5. print val

What would you expect the output of those to be? Probably 1, 1, and 10 right?

Wrong.

The actionscript example comes out to 0.9999999999999999, java has 1.0000001, and ruby gets 9.99999999999998

Here’s another actionscript example:

  1. trace( (0.1 + 0.1 ) == (2/10) );
  2. trace( (0.1 + 0.1 + 0.1) == (3/10) );

That traces out:
true
false

Baffling huh? A float should easily have the precision to represent a tenth, right? It should easily be able to add up ten tenths to get one, right?

Here’s the problem. Floats really operate in binary (duh). In binary, you can’t represent a lot of simple decimal values, such as 0.10 without a repeating pattern. 0.10 decimal works out to 0.000110011 in binary, with the last 4 digits repeating forever. So the 0.1 you see when you trace out 0.1 is really just a rounded off binary value. If you do math with those values, the error can accumulate until it’s big enough to be seen despite the rounding.

So you should never use floats for anything like:

  • Money
  • “Real mathematics” (for instance, I work on educational math software where the numbers have to always actually add up)
  • Anything requiring a certain precision, like sending a probe to mars or calculating medication dosage

You should use floats for things where precision doesn’t really matter.  Things, that if you’re off by a little nobody will ever notice.  Games, animations, audio compression, etc.   Otherwise, the easiest solution is to stick to integer based math.  You can pick a unit of measure magnitudes higher than you need.  Example: for money use cents (or thenths of cents?) instead of dollars as your UoM.  Then when you display the value you divide by 100 to show dollars.  Or you could use a richer class that handles precise numbers like Java’s BigDecimal, or ruby’s Rational type.

But like I said, we already knew this, right?

Creating nested objects with JSON in Rails


Notice: Undefined index: STRICT_MODE_APPLIES in /var/www/html/rogue-development/blog2/wp-content/plugins/deans_code_highlighter/geshi.php on line 1036

Did you know it’s possible to send a single JSON based request to a stanard rails controller and have it create an object, plus an entire tree of children records?  I knew it was possible, but I was wracking my brain trying to figure out how to do it for several days. Imagine you have a data model something like this:

  1. class Commute < ActiveRecord::Base
  2.   has_many :locations
  3. end
  4.  
  5. class Location < ActiveRecord::Base
  6.   belongs_to :commute
  7. end

That’s a pretty simple many-to-one relationship.  Now, if you have a regular old Rails controller, how do you pass that single JSON request to create both the commute object, as well as several location children?

The first step is to add the accepts_nested_attributes_for attribute to the commute model object.

  1. class Commute < ActiveRecord::Base
  2.   has_many :locations
  3.   accepts_nested_attributes_for :locations, :allow_destroy => true
  4. end

And… that’s it on the server side!

To use this functionality, your client should send a PUT request with the following JSON in the body:

  1. {
  2.     "commute": {
  3.         "minutes": 0,
  4.         "startTime": "Wed May 06 22:14:12 EDT 2009",
  5.         "locations_attributes": [
  6.             {
  7.                 "latitude": "40.4220061",
  8.                 "longitude": "127.4220061"
  9.             },
  10.             {
  11.                 "latitude": "42.4220061",
  12.                 "longitude": "41.4220061"
  13.             }
  14.         ]
  15.     }
  16. }

minutes and starttime are two properties of the commute object. And likewise latitude and longitude are two properties of the location objects.
The only thing strange there is instead of passing a locations array, you have to pass a locations_attributes array. The “_attributes” is the magic piece that I couldn’t figure out.  This lets Rails know you want it to figure out how to create the children, and you’re not simply passing those children in.

If you don’t put the _attributes suffix in, you’ll get errors like the following because Rails is creating a generic hash and trying to shove that into where a Location object should go.

ActiveRecord::AssociationTypeMismatch (Location(#18269790) expected, got HashWithIndifferentAccess(#2654720)):

This general approach should work with XML or HTTP params based requests as well.