61
© 2013 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential. JavaScript Puzzlers: Puzzles to Make You Think (and write fewer bugs) Charles Bihis | Computer Scientist 1

JavaScript Puzzlers!

Embed Size (px)

DESCRIPTION

Stay alert and try to solve these "simple" JavaScript puzzles, designed to demonstrate some of the more obscure "features" of the language. Try your best to answer them! But, be careful — the solutions aren't as easy as they look.

Citation preview

Page 1: JavaScript Puzzlers!

© 2013 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

JavaScript Puzzlers: Puzzles to Make You Think (and write fewer bugs)Charles Bihis | Computer Scientist

1

Page 2: JavaScript Puzzlers!

© 2013 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

Who am I?

Charles Bihis Computer Scientist

Adobe Identity Team

Blog: blogs.adobe.com/charles

Twitter: @charlesbihis

GitHub: github.com/charlesbihis

2

Page 3: JavaScript Puzzlers!

© 2013 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

What can I expect?

What are we going to talk about?

Puzzlers!

Maximus the Confused!

Block Party!

That’s Odd!

Let’s Print Some ZIP-Codes!

Say What?!

Loopty Loop!

A Case of Mistaken Identity

Why Are We Bankrupt?!

Will deal with only pure JavaScript

(i.e. no libraries!)

3

What are we NOT going to talk about?

3rd- party libraries or frameworks

e.g. jQuery, Node.js, etc.

Bugs

Page 4: JavaScript Puzzlers!

© 2013 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

What is a Puzzler?

A Puzzler is a very simple programming puzzle that demonstrates or exploits

weird behaviours and quirky edge-cases of a given programming language.

4

Page 5: JavaScript Puzzlers!

© 2013 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

How does this work?

1. Code – I introduce the code.

2. Question – I pose a multiple-choice question and you guess what the

answer is…think hard!

3. Walkthrough – I walk through a reasonable explanation.

4. Answer – I tell you the real answer.

5. Moral – How can you avoid making mistakes like this in your own code.

5

Page 6: JavaScript Puzzlers!

© 2013 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

JavaScript Puzzler – Maximus the Confused!

6

var commodusRule = 'thumbsUp';

alert('Maximus the ' + (commodusRule === 'thumbsUp') ? 'Gladiator' : 'Merciful');

What does this print?

a) Maximus the Gladiator

b) Maximus the Merciful

c) Error

d) None of the above

prints only "Gladiator"

Page 7: JavaScript Puzzlers!

© 2013 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

But why?

Order of operations dictates that the binary “+” operator takes precedence over the conditional “?”

operator.

7

*Reference: https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/Operator_Precedence

'Maximus the ' + (commodusRule === 'thumbsUp') ? 'Gladiator' : 'Merciful';

Page 8: JavaScript Puzzlers!

© 2013 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

But why?

Order of operations dictates that the binary “+” operator takes precedence over the conditional “?”

operator.

8

*Reference: https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/Operator_Precedence

'Maximus the true' ? 'Gladiator' : 'Merciful';

Page 9: JavaScript Puzzlers!

© 2013 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

But why?

Order of operations dictates that the binary “+” operator takes precedence over the conditional “?”

operator.

9

*Reference: https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/Operator_Precedence

'Gladiator';

Page 10: JavaScript Puzzlers!

© 2013 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

But why?

Order of operations dictates that the binary “+” operator takes precedence over the conditional “?”

operator.

According to the MDN (Mozilla Developer Network), the binary “+” operator has a precedence of 6

while the conditional “?” operator has a precedence of 15.

Note: This is below MOST commonly used operators (i.e. “*”, “/”, “%”, “<“, “>>” “!=”, “===“, etc).

10

*Reference: https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/Operator_Precedence

'Gladiator';

Page 11: JavaScript Puzzlers!

© 2013 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

JavaScript Puzzler – Maximus the Confused…FIXED!

11

var commodusRule = 'thumbsUp';

alert('Maximus the ' + (commodusRule === 'thumbsUp') ? 'Gladiator' : 'Merciful');

Page 12: JavaScript Puzzlers!

© 2013 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

JavaScript Puzzler – Maximus the Confused…FIXED!

12

var commodusRule = 'thumbsUp';

alert('Maximus the ' + (commodusRule === 'thumbsUp' ? 'Gladiator' : 'Merciful'));

Page 13: JavaScript Puzzlers!

© 2013 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

Moral

Be aware of order-of-operations!

Be explicit and place parenthesis accordingly to ensure correct

and predictable order of execution.

13

Page 14: JavaScript Puzzlers!

© 2013 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

JavaScript Puzzler – Block Party!

// global var

var name = "World!";

(function() {

// check if "name" defined

if (typeof name === "undefined") {

// local "shadow" var

var name = "Mr. Bond.";

alert("Hello, " + name);

} else {

alert("Hello, " + name);

}

})();

14

What does this print?

a) “Hello, World!”

b) “Hello, Mr. Bond.”

c) “Hello, ”

d) None of the above

Page 15: JavaScript Puzzlers!

© 2013 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

But why?

1. No block scope!

2. “Hoisting”

15

for (var i = 0; i < MAX; i++)

{

// do something

}

alert(i); // Note: "i" exists here!

alert(i);

for (var i = 0; i < MAX; i++)

{

// do something

}

// Note: "i" exists here too!

Page 16: JavaScript Puzzlers!

© 2013 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

But why?

1. No block scope!

2. “Hoisting”

16

for (var i = 0; i < MAX; i++)

{

// do something

}

alert(i); // Note: "i" exists here!

var i;

alert(i); // Note: "i" exists here too!

for (i = 0; i < MAX; i++)

{

// do something

}

Page 17: JavaScript Puzzlers!

© 2013 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

JavaScript Puzzler – Block Party…FIXED!

// global var

var name = "World!";

(function() {

// check if "name" defined

if (typeof name === "undefined") {

// local "shadow" var

var name = "Mr. Bond.";

alert("Hello, " + name);

} else {

alert("Hello, " + name);

}

})();

17

Page 18: JavaScript Puzzlers!

© 2013 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

JavaScript Puzzler – Block Party…FIXED!

// global var

var name = "World!";

(function() {

var name;

// check if "name" defined

if (typeof name === "undefined") {

// local "shadow" var

name = "Mr. Bond.";

alert("Hello, " + name);

} else {

alert("Hello, " + name);

}

})();

18

// declaration hoisted here

// assignment remains here

Page 19: JavaScript Puzzlers!

© 2013 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

JavaScript Puzzler – Block Party…FIXED!

// global var

var name = "World!";

(function() {

var name = "Mr. Bond.";

// check if "name" defined

if (typeof name === "undefined") {

alert("Hello, " + name);

} else {

alert("Hello, " + name);

}

})();

19

Page 20: JavaScript Puzzlers!

© 2013 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

Moral

There is no block-level scoping in JavaScript

Declare ALL of your variables at the top of your function

20

Page 21: JavaScript Puzzlers!

© 2013 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

JavaScript Puzzler – That’s Odd!

(function(){

var values = [7, 4, '13', Infinity, -9];

for (var i = 0; i < values.length; i++) {

if (isOdd(values[i])) {

alert(values[i]);

}

}

})();

function isOdd(num) {

return num % 2 == 1;

}

21

What does this print?

a) 7, 13

b) 7, 13, Infinity, -9

c) 7, -9

d) 7, 13, -9

Page 22: JavaScript Puzzlers!

© 2013 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

But why?

Let’s take a closer look…

22

7 % 2 = 1 // displays

4 % 2 = 2 // does NOT display

13 % 2 = 1 // displays

Infinity % 2 = NaN // does NOT display

-9 % 2 = -1 // does NOT display

Page 23: JavaScript Puzzlers!

© 2013 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

But why?

-9 % 2 = -1? Really?

JavaScript shares the same behavior as the Java implementation of the modulus (%) operator. That is, it must satisfy the following identity function for all integer values a and non-zero integer

values b.

A side-implication of this behavior is that the result will have the same sign as the left operand!

23

(a / b) * b + (a % b) == a

Page 24: JavaScript Puzzlers!

© 2013 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

JavaScript Puzzler – That’s Odd…FIXED!

(function(){

var values = [7, 4, '13', Infinity, -9];

for (var i = 0; i < values.length; i++) {

if (isOdd(values[i])) {

alert(values[i]);

}

}

})();

function isOdd(num) {

return num % 2 == 1;

}

24

Page 25: JavaScript Puzzlers!

© 2013 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

JavaScript Puzzler – That’s Odd…FIXED!

(function(){

var values = [7, 4, '13', Infinity, -9];

for (var i = 0; i < values.length; i++) {

if (isOdd(values[i])) {

alert(values[i]);

}

}

})();

function isOdd(num) {

return num % 2 != 0;

}

25

Page 26: JavaScript Puzzlers!

© 2013 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

Moral

Be careful about the signs of operands when using the modulus

operator.

26

Page 27: JavaScript Puzzlers!

© 2013 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

JavaScript Puzzler – Let’s Print Some ZIP Codes!

27

What does this print?

a) 93021

19

20341

32959

b) 93021

2392

20341

8163

32959

c) 93021

20341

32959

d) It varies

// array of 5 valid zip-codes

var zipCodes = new Array("93021",

"02392",

"20341",

"08163",

"32959");

// let's do something with each zip-code

// for now, display them

for (var i = 0; i < zipCodes.length; i++) {

// sanity check

if (!isNaN(parseInt(zipCodes[i])) &&

parseInt(zipCodes[i]) > 0) {

alert(parseInt(zipCodes[i]));

}

}

Firefox

Chrome

Page 28: JavaScript Puzzlers!

© 2013 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

But why?

Syntax

When you omit the optional “radix” parameter, the following behavior takes place:

If the input string begins with “0x” or “0X”, radix of 16 is used (i.e. hexadecimal)

If the input string begins with “0”, radix 8 is used (i.e. octal) OR radix 10 is used (i.e. decimal)

If the input string begins with any other values, radix 10 is used (i.e. decimal)

Particularly when dealing with string values with leading 0’s, Mozilla had this to say…

28

var num = parseInt(string, radix); // "radix" is optional

Exactly which radix is chosen is implementation-dependent.

For this reason ALWAYS SPECIFY A RADIX WHEN USING parseInt.

*Reference: https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/parseInt

Page 29: JavaScript Puzzlers!

© 2013 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

But why?

Another important note about the parseInt() API…

A closer look…

29

parseInt("93021") = 93021 // displays

parseInt("02392") = (2 * 8) + (3 * 1) = 19 // displays

parseInt("20341") = 20341 // displays

parseInt("08163") = 0 // does NOT display

parseInt("32959") = 32959 // displays

*Reference: https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/parseInt

If parseInt encounters a character that is not a numeral in the

specified radix, it ignores it and all succeeding characters

and returns the integer value parsed up to that point.

Page 30: JavaScript Puzzlers!

© 2013 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

JavaScript Puzzler – Let’s Print Some ZIP Codes…FIXED!

30

// array of 5 valid zip-codes

var zipCodes = new Array("93021",

"02392",

"20341",

"08163",

"32959");

// let's do something with each zip-code

// for now, display them

for (var i = 0; i < zipCodes.length; i++) {

// sanity check

if (!isNaN(parseInt(zipCodes[i])) &&

parseInt(zipCodes[i]) > 0) {

alert(parseInt(zipCodes[i]));

}

}

Page 31: JavaScript Puzzlers!

© 2013 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

JavaScript Puzzler – Let’s Print Some ZIP Codes…FIXED!

31

// array of 5 valid zip-codes

var zipCodes = new Array("93021",

"02392",

"20341",

"08163",

"32959");

// let's do something with each zip-code

// for now, display them

for (var i = 0; i < zipCodes.length; i++) {

// sanity check

if (!isNaN(parseInt(zipCodes[i], 10)) && // radix value added

parseInt(zipCodes[i], 10) > 0) { // here too

alert(parseInt(zipCodes[i], 10)); // and here too

}

}

Page 32: JavaScript Puzzlers!

© 2013 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

Moral

parseInt() takes an optional radix parameter.

Omitting this optional parameter will cause unpredictable

behavior across browsers.

Be explicit and ALWAYS include the radix parameter.

32

Page 33: JavaScript Puzzlers!

© 2013 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

JavaScript Puzzler – Say What?!

33

What does this print?

a) alert("BOOM!“);

b) Hello, </script><script>alert("BOOM!");</script>

c) BOOM!

d) Error

function sayHello(name) {

alert('Hello, ' + name);

}

sayHello('</script><script>alert("BOOM!");</script>');

Page 34: JavaScript Puzzlers!

© 2013 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

But why?

Let’s take a look at the code again…

34

function sayHello(name) {

alert('Hello, ' + name);

}

sayHello('</script><script>alert("BOOM!");</script>');

Page 35: JavaScript Puzzlers!

© 2013 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

But why?

Let’s take a look at the code again…

When a browser renders a page, first the HTML parser will parse the page and tokenize out all of

the tags.

Only after this is done, will it then allow the JavaScript parser to tokenize and execute whatever

tokens the HTML parser believes are JavaScript scripts!

35

<script>

function sayHello(name) {

alert('Hello, ' + name);

}

sayHello('</script><script>alert("BOOM!");</script>');

</script>

Page 36: JavaScript Puzzlers!

© 2013 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

But why?

Let’s take a look at the code again…

Armed with this knowledge, we can see that the HTML parser will send 2 scripts to the JavaScript

parser to tokenize and execute…

<script>function sayHello(name) { alert('Hello, ' + name); } sayHello('</script>

<script>alert("BOOM!");</script>

36

<script>

function sayHello(name) {

alert('Hello, ' + name);

}

sayHello('</script><script>alert("BOOM!");</script>');

</script>

Page 37: JavaScript Puzzlers!

© 2013 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

A closer look

Again, the HTML parser will send these two script tags to the JavaScript parser…

<script>function sayHello(name) { alert('Hello, ' + name); } sayHello('</script>

<script>alert("BOOM!");</script>

If that name parameter is user-controlled, perhaps taken as input from the browser, or pulled from

a datasource, whatever, then this is an open invitation for XSS attacks!

Errors like this can expose huge security holes which may allow an attacker to potentially take

over a user’s browser!

37

Page 38: JavaScript Puzzlers!

© 2013 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

JavaScript Puzzler – Say What?!...FIXED!

In this particular case, the fix must be done on the server-side.

We want to eliminate the <script></script> tags from appearing in the source in the first place.

Suggested solution is to use the OWASP ESAPI APIs…

Stands for “The Open Web Application Security Project” “Enterprise Security API”

https://www.owasp.org/index.php/Category:OWASP_Enterprise_Security_API

Have API bindings in all major languages including…

Java

Dot NET

PHP

JavaScript

Python

PHP

38

Page 39: JavaScript Puzzlers!

© 2013 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

JavaScript Puzzler – Say What?!...FIXED!

For this particular Puzzler, we want to use ESAPI.encoder().encodeForJavaScript()

Doing this on the server to JavaScript-encode the user-inputted variable, name, we get what we expect…

39

Page 40: JavaScript Puzzlers!

© 2013 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

Moral

NEVER . TRUST . THE . USER

Validate your input.

Encode your output appropriately.

i.e. HTML-encode for HTMLURL-encode for URLsJavaScript-encode for JavaScriptetc.

Use standard libraries (i.e. don’t reinvent the wheel).

40

Page 41: JavaScript Puzzlers!

© 2013 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

JavaScript Puzzler – Loopty Loop!

41

What does this print?

a) 0

b) 100

c) 101

d) None of the above

var END = 9007199254740992;

var START = END - 100;

var count = 0;

for (var i = START; i <= END; i++) {

count++;

}

alert(count);

enters infinite loop

// Math.pow(2, 53)

Page 42: JavaScript Puzzlers!

© 2013 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

But why?

9007199254740992 is a special number. Particularly, it is 2^53.

Why is this special?

First, we need to know something about how JavaScript represents numbers.

42

*Reference: http://ecma262-5.com/ELS5_HTML.htm#Section_8.5

Page 43: JavaScript Puzzlers!

© 2013 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

But why?

JavaScript numbers abide by the IEEE Standard for Floating-Point Arithmetic (IEEE 754).

As such, all numbers in JavaScript are represented by double-precision 64-bit floating point

values…

In binary…

43

*Reference: http://ecma262-5.com/ELS5_HTML.htm#Section_8.5

1.2345 = 12345 10x-4

mantissa

exponent

1 11...111 11111111111...111

63 62 53 52 0

exponent mantissasign

Page 44: JavaScript Puzzlers!

© 2013 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

But why?

2^53 is the largest exact integral value that can be represented in JavaScript!

From the ECMA specification…

What does this mean?

44

*Reference: http://ecma262-5.com/ELS5_HTML.htm#Section_8.5

Note that all the positive and negative integers whose magnitude

is no greater than 2^53 are representable in the Number type.

var numA = Math.pow(2, 53);

var numB = numA + 1;

alert(numA === numB); // true!

Page 45: JavaScript Puzzlers!

© 2013 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

JavaScript Puzzler – Loopty Loop…FIXED!

45

var END = 9007199254740992; // Math.pow(2, 53)

var START = END - 100;

var count = 0;

for (var i = START; i <= END; i++) {

count++;

}

alert(count);

Page 46: JavaScript Puzzlers!

© 2013 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

JavaScript Puzzler – Loopty Loop…FIXED!

46

var START = 0;

var END = 100;

var count = 0;

for (var i = START; i <= END; i++) {

count++;

}

alert(count);

Page 47: JavaScript Puzzlers!

© 2013 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

Moral

Be aware of your number representations and number ranges!

There are REAL limitations imposed by your computer. When

dealing with large (or important) numbers, know them!

47

Page 48: JavaScript Puzzlers!

© 2013 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

JavaScript Puzzler – A Case of Mistaken Identity!

function showCase(value) {

switch(value) {

case "A":

alert("Case A was selected.");

break;

case "B":

alert("Case B here!");

break;

case "C":

alert("This is Case C.");

break;

default:

alert("Don't know what happened.");

break;

}

}

showCase(new String("A"));

48

What does this print?

a) Case A was selected.

b) This is Case C.

c) Error

d) Don’t know what

happened.

Page 49: JavaScript Puzzlers!

© 2013 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

But why?

The switch statement in JavaScript internally uses the strict equality operator (i.e. ===) as opposed

to the non-strict equality operator (i.e. ==).

The strict equality operator behaves exactly as the non-strict version, except that no type-

conversions are done.

So, when the switch statement evaluates equality, it checks that the following are true…

Their types are equal

Their uncast values are equal

Notice, we invoked showCase() with a new String object.

49

alert(typeof "A"); // "string"

alert(typeof new String("A")); // "object"

Page 50: JavaScript Puzzlers!

© 2013 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

JavaScript Puzzler – A Case of Mistaken Identity…FIXED!

function showCase(value) {

switch(value) {

case "A":

alert("Case A was selected.");

break;

case "B":

alert("Case B here!");

break;

case "C":

alert("This is Case C.");

break;

default:

alert("Don't know what happened.");

break;

}

}

showCase(new String("A"));

50

Page 51: JavaScript Puzzlers!

© 2013 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

JavaScript Puzzler – A Case of Mistaken Identity…FIXED!

function showCase(value) {

switch(value) {

case "A":

alert("Case A was selected.");

break;

case "B":

alert("Case B here!");

break;

case "C":

alert("This is Case C.");

break;

default:

alert("Don't know what happened.");

break;

}

}

showCase("A");

51

Page 52: JavaScript Puzzlers!

© 2013 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

Moral

Get used to using the strict equality operator when possible. It will make you more aware of type

conversions and true equalities.

From Douglas Crockford’s book “JavaScript: The Good Parts”…

52

JavaScript has two sets of equality operators: === and !==, and their evil twins == and !=.

The good ones work the way you would expect. The evil twins do the right thing when the

operands are of the same type, but if they are of different types, they attempt to coerce the

values, the rules by which they do that are complicated and unmemorable.

Page 53: JavaScript Puzzlers!

© 2013 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

JavaScript Puzzler – Why Are We Bankrupt?!

53

What does this print?

a) 0

b) 0.2

c) 0.20

d) None of the above

var costOfCandy = 0.60; // 60 cents

function calculateChange(cost, paid) {

return paid - cost;

}

// pay for candy with 80 cents

alert(calculateChange(costOfCandy, 0.80));

0.20000000000000007

Page 54: JavaScript Puzzlers!

© 2013 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

But why?

As we learned from a previous Puzzler, all JavaScript numbers use the IEEE 754 floating-point

arithmetic specification.

Because of this, values are not represented exactly, but rather as a fraction.

Some non-integer values simply CANNOT be expressed exactly in this way. They must be

approximated.

54

Example:

123.45 = 12345 * 10^-2 // exact

1 / 3 = 0.333333333333333 * 10^0 // approximation!

Page 55: JavaScript Puzzlers!

© 2013 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

JavaScript Puzzler – Why Are We Bankrupt?!...FIXED!

55

var costOfCandy = 0.60; // 60 cents

function calculateChange(cost, paid) {

return paid - cost;

}

// pay for candy with 80 cents

alert(calculateChange(costOfCandy, 0.80));

Page 56: JavaScript Puzzlers!

© 2013 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

JavaScript Puzzler – Why Are We Bankrupt?!...FIXED!

56

var costOfCandy = 60; // 60 cents

function calculateChange(cost, paid) {

return paid - cost;

}

// pay for candy with 80 cents

alert(calculateChange(costOfCandy, 80));

// Use only integer math when dealing with money! To do this,

// represent your money in terms of cents to begin with!

//

// e.g. use 1599 instead of 15.99 to represent $15.99

Page 57: JavaScript Puzzlers!

© 2013 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

Moral

Floating-point arithmetic can be inaccurate when representing fractions.

When dealing with money, deal in terms of cents! This makes all of your calculations integer-

calculations, which are exact!

Not completely exact, though…

Remember from our last Puzzler, it is exact only up until the largest representable integer value…

9007199254740992 (i.e. 2^52)

So, as long as you are dealing with less than $9 quintillion, you’re fine using integer arithmetic in

JavaScript :)

57

*Reference: http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html

Page 58: JavaScript Puzzlers!

© 2013 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

That’s it!

Questions?

58

Page 59: JavaScript Puzzlers!

© 2013 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

Any favorites?

Puzzlers!

Maximus the Confused!

Block Party!

That’s Odd!

Let’s Print Some ZIP-Codes!

Say What?!

Loopty Loop!

A Case of Mistaken Identity

Why Are We Bankrupt?!

59

Page 60: JavaScript Puzzlers!

© 2013 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

Thanks for coming!

Charles Bihis Computer Scientist

Adobe Identity Team

Blog: blogs.adobe.com/charles

Twitter: @charlesbihis

GitHub: github.com/charlesbihis

60

Page 61: JavaScript Puzzlers!

© 2013 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.