Monthly Archives: March 2013

story about left shift

I was tinkering with Ofront, making changes here and there in order to run it on x86_64.
By doing this I met a strange warning issued by gcc when it was compiling Console.c file.

Console.c: In function ‘Console_Int’:
Console.c:57:2: warning: left shift count >= width of type [enabled by default]

So, Console.c is generated from Console.Mod. And the Int function of Console module writes integer to the console.
This is how it looks:

  PROCEDURE Int*(i, n: LONGINT);
    VAR s: ARRAY 32 OF CHAR; i1, k: LONGINT;
  BEGIN
    IF i = SYSTEM.LSH(LONG(LONG(1)), SIZE(LONGINT)*8 - 1) THEN
      IF SIZE(LONGINT) = 8 THEN s := "8085774586302733229"; k := 19
      ELSE s := "8463847412"; k := 10
      END
    ELSE
      i1 := ABS(i);
      s[0] := CHR(i1 MOD 10 + ORD("0")); i1 := i1 DIV 10; k := 1;
      WHILE i1 > 0 DO s[k] := CHR(i1 MOD 10 + ORD("0")); i1 := i1 DIV 10; INC(k) END
    END ;
    IF i < 0 THEN s[k] := "-"; INC(k) END ;
    WHILE n > k DO Char(" "); DEC(n) END ;
    WHILE k > 0 DO  DEC(k); Char(s[k]) END
  END Int;

The error is issued in the line:

    IF i = SYSTEM.LSH(LONG(LONG(1)), SIZE(LONGINT)*8 - 1) THEN

which is translated as following in case of x86_64:

if (i == __LSHL(1, 63, LONGINT)) {

On x86 it gets translated as:

if (i == __LSHL(1, 31, LONGINT)) {

Okay, and it does not issue an error on 32 bit platform, Why?

Probably, need to look into how the _LSHL macro is written. That’s in SYSTEM.h

#define __LSHL(x, n, t) ((t)((unsigned)(x)<<(n)))

Okay, what do we see. It casts the number as unsigned, then shifts it. Obviously, the cast is necessary in order to use the sign bit.

Now let's swerve to the question why do they to do this?
And what special in this "8085774586302733229" number? Or in this: "8463847412"? If you fed this number to the Worlfram alpha saas, it does not give a clue.
The clue gives the lower part of the script, it writes the number from right to left.

WHILE k > 0 DO  DEC(k); Char(s[k]) END

Let's reverse this number and look at it as binary.

noch@SAL9000 ~ $ echo 'obase=2; 2147483648' | bc
10000000000000000000000000000000

wow. This is it. We would get it by shifting 1 to the left.
But why do they shift it?
What is LONGINT on 32 bit platform? It is a number in range from -2^31 .. 2^31 -1.
And the number 2147483648 is 2^31.
So they do it in order to be able to print the number 2^31! Only for that!
Obviously, in case of x86_64 that's the number 9,223,372,036,854,775,808

Okay, let's tinker further. We want to be able to print it, why not?

So why C compiler (I use gcc) does not issue
the warning in case of 32 bits but issues in case of 64?

Because of the macro, probably. Let's write a simple C text to check.

#include "stdio.h"
#define __LSHL(x, n, t) ((t)((unsigned)(x)<<(n)))

int main()
{
   long i;
   printf("%lu\n",sizeof(long));

   i=__LSHL(1, sizeof(long)*8-1, long);

   printf ("%lu\n",i);
return 0;

}

Then,

$ gcc -o test0 test0.c
test0.c: In function ‘main’:
test0.c:9:4: warning: left shift count >= width of type [enabled by default]

The problem is in the cast. If we do (unsigned) then it casts it to unsigned int, not unsigned long.
Let's change the macro to

#define __LSHL(x, n, t) ((t)((unsigned t)(x)<<(n)))

Now it compiles without warnings and run.

$ gcc -o test0 test0.c
$ ./test0
8
9223372036854775808

However, compiler fails to compile it when we make the same change in SYSTEM.h

Console.c: In function ‘Console_Int’:
Console.c:56:11: error: expected ‘)’ before ‘LONGINT’

Why?
Let's emulate the case exactly. We need to add LONGINT typedef

#include "stdio.h"
typedef long LONGINT;
#define __LSHL(x, n, t) ((t)((unsigned t)(x)<<(n)))

int main()
{
   long i;
   printf("%lu\n",sizeof(LONGINT));

   i=__LSHL(1, sizeof(LONGINT)*8-1, LONGINT);

   printf ("%lu\n",i);
return 0;

}

It does not compile!

noch@SAL9000 /tmp $ gcc -o test1 test1.c
test1.c: In function ‘main’:
test1.c:10:6: error: expected ‘)’ before ‘LONGINT’

We clearly see that in the macro there are three arguments which _LSHL expects but for some strange reason gcc expects the closing parentheses after the second argument.
However we can compile it with g++ - it understands this typedef issue

noch@SAL9000 /tmp $ cp test1.c test1.cpp
noch@SAL9000 /tmp $ g++ -o test1 test1.cpp
noch@SAL9000 /tmp $ ./test1
8
9223372036854775808
noch@SAL9000 /tmp $

Okay. What can be done here?
We can do

typedef unsigned long ULONGINT;

and then change macro like this:

#define __LSHL(x, n, t) ((t)((ULONGINT)(x)<<(n)))

So the file looks like

#include "stdio.h"
typedef long LONGINT;
typedef unsigned long ULONGINT;
#define __LSHL(x, n, t) ((t)((ULONGINT)(x)<<(n)))
//#define __LSHL(x, n, t) ((t)((unsigned t)(x)<<(n)))

int main()
{
   long i;
   printf("%lu\n",sizeof(LONGINT));

   i=__LSHL(1, sizeof(LONGINT)*8-1, LONGINT);

   printf ("%lu\n",i);
return 0;

}

now, and it compiles

$ gcc -o test test.c
$ ./test
8
9223372036854775808

But this is not what we want.
The good solution would be to replace a macro with a function, which can be debugged, and which won't give such an error. But it is not possible to pass a type as an argument in plain C without a macro. It may be possible by using templates, in C++, but we use C.
May be there is a need to change Ofront in a way it would generate a different function call.
Another solution is to use define instead of typedef.

#include "stdio.h"
//typedef long LONGINT;
#define LONGINT long

//typedef unsigned long ULONGINT;
//#define __LSHL(x, n, t) ((t)((ULONGINT)(x)<<(n)))
#define __LSHL(x, n, t) ((t)((unsigned t)(x)<<(n)))

int main()
{
   long i;
   printf("%lu\n",sizeof(LONGINT));

   i=__LSHL(1, sizeof(LONGINT)*8-1, LONGINT);

   printf ("%lu\n",i);
return 0;

}

Test runs

$ gcc -o test test.c
$ ./test
8
9223372036854775808

For now the solution is to replace typedef with define in SYSTEM.h and use (unsigned t) cast in the macro.

und so weiter

story about one death

657996CC-5DC6-423E-BB5C-C7B1B1CA0B96_w443_r1

Today, many years ago a dictator named Stalin died.

As House once said, almost dying changes nothing. Dying changes everything.

So this allowed us to stop devastation of the Sevan lake, it allowed us to free some political prisoners, such as Mahari (though it was too late to help Charents), it allowed us to get rid of the huge Stalin monument over the Yerevan,
monument-to-stalin---yerevan---1962

it allowed us to have our 60ies, to speak about armenian genocide, and build a memorial where we can bring flowers and not be arrested, to have new, interesting architecture, like openhall, or a seagull for which Khrushchev punished Zarobian, it allowed us to breath a little more free, fresh air, it allowed some short change.
When it is someone’s birthday, people say – how cool that you’d born, and when people like Stalin die, it’s time to say – how cool that you died, thank you for that, it’s possibly the best thing you could do, and it was very nice for Armenia.

openhall

ruben17-1

seagull

und so weiter

story about smell of money

spent several months programming in Java. Contrary to its authors prediction, it did not grow on me. I did not find any new insights – for the first time in my life programming in a new language did not bring me new insights. It keeps all the stuff that I never use in C++ – inheritance, virtuals – OO gook – and removes the stuff that I find useful. It might be successful – after all, MS DOS was – and it might be a profitable thing for all your readers to learn Java, but it has no intellectual value whatsoever. Look at their implementation of hash tables. Look at the sorting routines that come with their “cool” sorting applet. Try to use AWT. The best way to judge a language is to look at the code written by its proponents. “Radix enim omnium malorum est cupiditas” – and Java is clearly an example of a money oriented programming (MOP). As the chief proponent of Java at SGI told me: “Alex, you have to go where the money is.” But I do not particularly want to go where the money is – it usually does not smell nice there.

source

und so weiter