Numbers in Dart

(This is part 10 in an ongoing series about Dart. Check out part 9, a Dart SDK quick tour.)

Intro

It's time to look at numbers in Dart. Wait, where are you going? Come back, numbers are cool! This will be interesting, for reals. I can at least promise this will be easy and quick, for numbers in Dart aren't complicated. If you're compiling to JavaScript, though, there are a few edge cases (bugs?) so I encourage you to not skip this episode.

The Basics

Like everything else in Dart, numbers are objects. In fact, numbers are specified as interfaces.

Numbers come in two flavors in Dart: integers of arbitrary size and decimal 64 bit doubles as specified by the IEEE 754 standard. Both int and double are subinterfaces of num.
num is the supertype, int and double extend num.
The num interface defines the basics like +, -, /, and *. Num is where you'll also find abs(), ceil(), and floor(), among other methods.

Int

Integers are numbers without a decimal point. For example:

  var x = 1;
  print(x);
  print(x is num); // true in both Dart VM and JS
  print(x is int); // true in both Dart VM and JS

You may also specify hexadecimals with the 0x prefix.

  var hex = 0xDEADBEEF;
  print(hex); // 873735928559
  print(hex is num); // true in both Dart VM and JS
  print(hex is int); // true in both Dart VM and JS
  print(hex is! double); // true in Dart VM, FALSE when compiled to JavaScript

Alert: the last line in the above sample, the result is different between the Dart VM and Dart compiled to JavaScript. I've opened a bug to see if this is by design.

Integers can be of arbitrary precision. For example:

  var bigInt = 346538465234590347592847298346243459756895347698465298346583746592374652378462347569234765834765947569827346583465243765923847659234765928347659567398475647495873984572947593470294387093493456870849216348723763945678236420938467345762304958724596873045876234572037862934765294365243652548673456705673465273465246734506873456729457623845623456234650457693475603768922346728346256;
  print(bigInt); // correct in Dart VM, Infinity when compiled to JavaScript
  print(bigInt is num); // true in both Dart VM and JS
  print(bigInt is int); // true in both Dart VM and JS

While the above will work in the Dart VM, when compiled to JavaScript, the large number becomes Infinity.

Alert: JavaScript only supports +/- 9007199254740992 for integers and (at least in V8) 1.7976931348623157e+308 for Number.MAX_VALUE. I've opened a bug to discuss this, as the above code functions differently in Dart VM and JavaScript.

You might see Dart code that explicitly adds a + prefix to the number, though it isn't necessary.

  var positive = +12345;
  print(positive); // 12345
  print(positive is num); // true
  print(positive is int); // true

Double

If the number includes a decimal, it is a 64 bit double that follows IEEE 754 standard.

A simple example:

  var y = 1.1;
  print(y);
  print(y is num); // true in both Dart VM and JS
  print(y is double); // true in both Dart VM and JS

Exponent notation is supported:

  var exponents = 1.42e5;
  print(exponents); // prints 142000.0 in Dart VM, 142000 when compiled to JavaScript
  print(exponents is num); // true in both Dart VM and JS
  print(exponents is! int); // true in Dart VM, FALSE when compiled to JS
  print(exponents is double); // true in both Dart VM and JS

Here again you can see slight differences between what Dart VM and JavaScript will do. The generated JavaScript code looks like this:

  // generated JavaScript from Frog, as of 2012-02-04
  var exponents = (142000.0);
  print(exponents);
  print((typeof(exponents) == 'number'));
  print((typeof(exponents) != 'number')); // this is FALSE, see corresponding Dart code above
  print((typeof(exponents) == 'number'));

NaN

Dividing zero by zero will result in "not a number" in Dart, similar to JavaScript but unlike Java.

The num interface provides a simple check for isNaN().

  var nan = 0 / 0;
  print(nan.isNaN()); // true in both Dart VM and JS

Converting to and from a String

A common requirement is to turn a number into a String, or a String into a number.

Parsing a String to an int uses the Math class:

  var one = Math.parseInt("1");
  print(one);  // 1
  print(one is int);  // true

Parsing a String into a double is similar:

  var onePointOne = Math.parseDouble("1.1");
  print(onePointOne); // 1.1
  print(onePointOne is double); // true

Attempting to format a string that isn't a number will throw a BadNumberFormatException.

  try {
    var gook = Math.parseInt("foo");
  } catch(BadNumberFormatException e) {
    print(e); // BadNumberFormatException: 'foo'
  }
  

Going the other way, converting numbers to Strings, is also very easy thanks to toString().

  String oneAsString = 1.toString();
  print(oneAsString); // 1
  print(oneAsString is String);

For doubles, toStringAsFixed(int fractionDigits) will truncate the decimal digits:

  print(3.14159.toStringAsFixed(2)); // 3.14

Misc methods

A potentially unfamiliar change is the methods like ceil() and abs() are found on the num interface, and not in Math.

  // absolute value is a method on num
  print((-4).abs() == 4);
  
  // ceil and floor are also methods on num
  print(3.25.ceil() == 4.0);
  print(3.25.floor() == 3.0);
  
  // round will round up if .5 or greater, otherwise will round down
  print(3.25.round() == 3);
  print(3.89.round() == 4);
  print(3.5.round() == 4);
  print(3.49.round() == 3);
  
  // truncates the decimal digits
  print(3.24532.truncate() == 3.0);
  
  // convert a double to an int
  print(3.24.toInt() == 3);

Bit manipulating

The num interface also specifies the traditional bit shifting, and'ing, and or'ing. Some simple examples:

  print(3<<1 == 6); // 0011 << 1 == 0110
  print(3>>1 == 1); // 0011 >> 1 == 0001
  
  print((3|4) == 7); // 0011 | 0100 == 0111

Summary

Dart supplies a num interface with two subinterfaces: int and double. Integers are arbitrary precision, meaning they have arbitrary size. Doubles are 64 bit decimals that follow IEEE 754 spec.

Generally speaking, numbers function the same across native Dart and Dart compiled to JavaScript, but there are some subtle differences. For example, watch out for very large numbers and checking the difference between int and double in JavaScript (currently everything is checked against number in JavaScript from the Frog compiler.)

Next Steps

Read more of my Dart posts, try Dart in your browser, browse the API docs, or file an issue request. Dart is getting ready, please send us your feedback!
5 comments

Popular posts from this blog

Converting Array to List in Scala

I ported a JavaScript app to Dart. Here's what I learned.

Minification is not enough, you need tree shaking