Alexander Minderov

Computers can divide by zero

We learned, many times, that we can't divide by zero.

First, in algebra, we learn that division by zero is impossible. Then, in calculus, we learn that it was a lie and division by zero is defined in most cases.

Then, in programming, we learn that division by zero is impossible and causes exceptions. It appears that it was a lie as well. IEEE has defined behaviour for division by zero for floats (per page 10 of IEEE 754).

Recall that in most implementation floating point has a sign (can be either -0.0 or 0.0).
With that in mind, let's look at interesting cases defined by IEEE 754:

// these three make sense from calculus perspective if we consider 0.0 to be very close to zero, but not zero
1.0/0.0 = Infinity
(±0.0)^(-2) = Infinity
(-0.0)^(-3) = -Infinity

// why does (-0.0)^(-3) have a negative sign but others have positive? This is a mystery to me
(-0.0)^(-2.99) = Infinity
(-0.0)^(-3) = -Infinity
(-0.0)^(-3.01) = Infinity

Why should I care?
I would not recommend using this behaviour in your programs to not confuse future code readers and maintainers, but it is useful to consider when thinking about edge-cases and debugging.

Potential problems might arise when code handles division by zero by catching exceptions. We now know that division by 0.0 would not be caught and would introduce issues down the line.

2018  

What are git commits?

There seems to be a confusion about how git commits are stored internally. When we use git it might look like commits are stored as a difference between versions of files. Most commands like git diff and git show display us the information as diffs, and never as the entire files. And it sounds like it makes sense to store only the changes too: we have large code bases but only make small changes at a time.

However, this awesome Pro Git Book states that all commits are snapshots of your current project. What that means is when you do `git commit` it doesn't just store the difference between the last and new commits, it stores the entire files!

One of my projects takes 20MB and it has 1066 commits. But running du -ch .git I can see that the entire git history takes only 34MB! How is that possible? Every commit is supposed to store the entire project, why does the entire commit history only take 70% more storage than the project itself?

Turns out the answer is git gc. Git automatically compresses older commits by storing just diffs. It saves a lot of space in exchange of decreased performance (e.g. when checking out old commits). It is a good trade-off considering most of the time older commits just sit there for redundancy without ever being used. However, if you need to, you can turn the compression off by running

git config --global gc.auto 0

Why should I care?
Understanding how git stores objects internally can help you make more educated decisions about how to organize your workflow. For example, binary files (images, library files, executables, etc) can't take advantage of diffs, so they are always stored as the entire file. Knowing all that, you would know downsides of storing frequently-updated binary files in git:

  • • dramatic increase in repository size,
  • • decrease in performance.
2018   git

Git bisect

Have you ever had a situation when you encounter a bug and you remember for sure that in the previous release (or just some time ago) it was working properly? Let's say you know that 800 commits ago that bug was not there and you can't find why it's happening, what are you going to do?

Turns out git has a very smart and simple feature called git bisect. The docs explain the usage very well, but here's a small example:


$ git bisect start
$ git bisect bad          # mark current commit as bad
$ git bisect good 91dd441 # mark commit 91dd441 as good

Then git outputs


Bisecting: 800 revisions left to test after this (roughly 10 steps)
[a1ea503523ae328eff7b6ca00e54316ec7665c3e] Commit name

and your journey begins! It shows that you will only need to test ~10 revisions to find the one where the bug was introduced, and the first one to check is the one being displayed on the second line. At this point git checked out your repository at this commit and all you need to do is recompile (or whatever you need to do to get the current code running) and see if the bug is still there.

If it's broken, you type git bisect bad, if not, you type git bisect good. Either way git will show you your current progress and the next commit to test:


Bisecting: 400 revisions left to test after this (roughly 9 steps)
[9a5caf8c0ec4b96f99f63186cc4fd50fda0aa242] Another commit name

Repeat 9 more times and git will tell you exactly in which commit the bug was introduced! If you follow good practices and keep commits short and compilable, it will now be much easier to fix the bug you were looking for.

Make sure to check out this beautiful Pro Git docs to learn more.

2018   git

Computers are very bad at math

Let's say you are creating an online store where customers can deposit money to increase their balance and then use the balance to buy things. You choose a time-tested and powerful language like C++.

Read the short code below and see if it makes sense:


// when a customer registers, set their balance to zero
float balance = 0.0; // in dollars


// customer deposited $12.20
balance += 12.2;


// customer is trying to buy something for $12.20,
// so you want to check if they have enough money for a purchase
if (balance >= 12.2) {
    // give the item to the customer
} else {
   // return a "not enough money" error
}

So this looks very simple. But this will actually throw a “not enough money” error. Because according to a computer

0.0 + 12.2 = 12.19999981

And there is nothing magical about number 12.2. Computer struggles with floating point arithmetic because there are many many numbers that can't be represented with a finite number of binary digits. If you are not careful, this will inevitably lead to errors that are really hard to debug.

In this case it is easily avoidable if you use integer and store balance in cents rather than in dollars, because any integer can be exactly represented in binary.

2017   C++

Checking if localStorage is available in JS

Update: In April 2017 Apple has changed this behaviour, so this post is now obsolete.

localStorage is a great feature supported by all modern browsers and even IE 8+, but before using it in your code you should make sure it is available in the browser.

On the internet you can find solutions that look very comprehensive:

var _supportsLocalStorage = !!window.localStorage
    && typeof localStorage.getItem === 'function'
    && typeof localStorage.setItem === 'function'
    && typeof localStorage.removeItem === 'function';

But using this code is dangerous. Let's take a look at an example:

var _supportsLocalStorage = !!window.localStorage
    && typeof localStorage.getItem === 'function'
    && typeof localStorage.setItem === 'function'
    && typeof localStorage.removeItem === 'function';

// save the data if localStorage is available
if (_supportsLocalStorage) {
    localStorage.setItem('foo', 'bar'); // this line gives an error in Private Tab in Safari
}

// continues with important code...

If we run this code in Private Tab in Safari, it will give us an error when setting a localStorage item, so all the important code after that will not run. That means that your website might very well be completely broken in Private Tab in Safari, and if you are working on your own small project you might not even know this is happening, especially if you are not developing on MacOS.

This happens because the solution above only checks if the functions exist, and in Safari in Private Tab these functions do exist, but do not work. Probably to make sure you can't be tracked.

Here is a function that covers this case:

function localStorageAvailable() {
    // if window.localStorage is not defined, return false right away
    if (window.localStorage) {
        var test = "__localStorageTest__";

        // try to use localStorage, and if it does not give any error, then it is available
        try {
            window.localStorage.setItem(test, test);
            window.localStorage.removeItem(test);
        } catch (ex) {
            return false;
        }

        return true;
    }

    return false;
};

It returns true if localStorage is available and ready to use, and false if it is

  • not supported, or
  • not allowed to be used, or
  • has no space left

If you do not plan to use localStorage extensively (storing a couple of megabytes worth of information there) this is good enough. But if you do, you've got another problem, which I will talk about next time.

Big takeaway: testing your website in all the browsers is not enough, you need to test them in private mods as well

2017