Much of the progress we see outside the window is the result of human laziness. Too lazy to paint the fence with a brush, invented a roller. Too lazy to paint with a roller, invented the spray gun. Well, you understand. What does all this have to do with programming? The most immediate!
Friend
The first programmers manipulated such concepts as "0" and "1" and this was long and incomprehensible. Human laziness offered using zeroes and ones to write a program that transforms MOV, ADD, JMP into new zeroes and ones that the processor understands.
In the future, laziness was not asleep and called instead of 6-10 lines of assembler to write 1 high-level command. Then more lazy things appeared. OOP, databases and so on and so forth. The programs became clearer and clearer, the search for errors was reduced by several times, thanks to various frameworks, the speed of development increased. High-level abstraction walked around the planet. And everyone was happy?
Enemy
But the enemy did not sleep! At one fine moment, the programmer is faced with a problem that at this level of abstraction cannot be solved, but even to understand where the problem grows from. In order to understand what is happening, you have to climb into the wilds of zeroes and ones. Examples? Yes please (all examples are given in C #).
')
Example 1
static void Main( string [] args)
{
double tenth = 0.1;
double first = 0;
for ( int i = 0; i < 10; i++)
{
first += tenth;
}
double eighth = 0.125;
double second = 0;
for ( int i = 0; i < 8; i++)
{
second += eighth;
}
Console .WriteLine(first == second);
Console .WriteLine( "0.1 * 10 = {0}\n0.125 * 8 = {1}" , first, second);
Console .ReadKey();
}
Try to assume that we will see on the screen.
Have tried? And what did you do? So, for those who suggested, well, for those who were lazy and just read it up to this place, I inform, we will see - False.

Notice that the values match? In principle, if we replace 10 with 100, and 8 with 80, then we will see that the values are different, but here it is O_o
Here it is the level of zeros and ones. In principle, understanding how floating-point numbers are represented, it is clear that 1/8 is nothing but 2 to -3 degrees and it will be folded without errors, but 0.1 can not be represented as a sum of integer powers of two in a modern double . Here is the error.
Continue?
Example 2
static void Main( string [] args)
{
int n = 10000;
int [,] array1 = new int [n, n];
int [,] array2 = new int [n, n];
for ( int i = 0; i < n; i++)
{
for ( int j = 0; j < n; j++)
{
array1[i, j] = 0;
array2[i, j] = 0;
}
}
DateTime begin = DateTime.Now;
for ( int i = 0; i < n; i++)
{
for ( int j = 0; j < n; j++)
{
array1[j, i]++;
}
}
Console .WriteLine( " [j, i] = {0}" , DateTime.Now.Subtract(begin).TotalSeconds);
begin = DateTime.Now;
for ( int i = 0; i < n; i++)
{
for ( int j = 0; j < n; j++)
{
array1[i, j]++;
}
}
Console .WriteLine( " [i, j] = {0}" , DateTime.Now.Subtract(begin).TotalSeconds);
Console .ReadKey();
}
The most amazing thing is that by changing the order of the indices when accessing the elements of the array, we get a change in the speed of work almost twice (on my computer, the first cycle worked in 2.16 seconds; the second in 1.13 seconds). With increasing n to 11000, the difference is already 5 times.
From where is the difference? Again with the level of zeros and ones. In this case, work with the cache is manifested and the fact that the two-dimensional array in memory is in fact one-dimensional.
Example 3
With the advent of generic types, this example may not be relevant, but still can not resist.
class MyPack
{
public int Value { get ; set ; }
}
static void Main( string [] args)
{
int n = 100000;
object [] array1 = new object [n];
object [] array2 = new object [n];
for ( int i = 0; i < n; i++)
{
array1[i] = 0;
array2[i] = new MyPack () { Value = 0 };
}
DateTime begin = DateTime .Now;
for ( int i = 0; i < n; i++)
{
array1[i] = ( int )array1[i] + 1;
}
Console .WriteLine( " c int = {0}" , DateTime .Now.Subtract(begin).TotalSeconds);
begin = DateTime .Now;
for ( int i = 0; i < n; i++)
{
(( MyPack )array2[i]).Value = (( MyPack )array2[i]).Value + 1;
}
Console .WriteLine( " MyPack = {0}" , DateTime .Now.Subtract(begin).TotalSeconds);
Console .ReadKey();
}
In the first case, the execution time was 0.017 seconds, in the second, 0.005 seconds. Here not so much low-level things come into force, but features of work with the conversion of simple types to the object type (anyone interested can be read about packaging and unpacking).
findings
To begin with, I do not think high-level abstraction is evil. And the title of the article, if you noticed, it’s about the fact that high-level abstraction is a friend to us, and so that it doesn’t turn into an enemy, let me read about the new architectures of Intel processors.
Ps At the time of writing, I went out into the corridor, where I ran into a colleague. So, he came up with the problem that when developing an application for Windows Mobile, the application works adequately until the PDA goes to sleep. When outputting it to the normal mode, the application is no longer in memory, there are no error messages, nothing. What do you think? I think that because of the hole in the high-level abstraction.