Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

How to write this sign function in Delphi.

56 views
Skip to first unread message

Skybuck Flying

unread,
Sep 21, 2015, 2:17:03 PM9/21/15
to
Hello,

Something strange going on with this C code, in Visual Studio 2010 the
result of Sign will be either -1, 0 or 1.

int Sign( int x )
{
return ((!!x) | (x >> 31));
}

int _tmain(int argc, _TCHAR* argv[])
{
printf("%d \n", Sign(-100));
printf("%d \n", Sign(0));
printf("%d \n", Sign(100));

return 0;
}

When trying to port this to Delphi it gives different results.

function IntegerSign( Para : integer ) : integer;
begin
result := ((not(not Para)) or (Para shr 31));
end;

function IntegerSign( Para : integer ) : integer;
begin
result := (Para xor (not Para)) or (Para shr 31));
end;

function IntegerSign( Para : integer ) : integer;
begin
result := (Para xor (-Para)) or (Para shr 31));
end;

Is there a way to write this C function in Delphi so it also returns -1, 0
and 1 in Delphi ???

Bye,
Skybuck.

Skybuck Flying

unread,
Sep 21, 2015, 2:43:39 PM9/21/15
to
Ok,

I've heard situations like this before...

I think one of the problems might be that C uses SAR instead of SHR.

Using SAR means "negativity" is kept when shifting.

So the negativity seems to be lost in Delphi.

the SAR 31 is a trick to isolate negativity versus positivity.

in Delphi/SHR this is lost and only zero or positivity is kept.

What remains unclear to me is the !! operator.

Is this a double not operator ?

Or something else ? ;)

At least now that I understand more of the problem I may be able to come up
with a solution in Delphi.

But first I gotta go eat ! ;) =D

To be continued...

Bye,
Skybuck.

P.S.: For the first time I am frying my supermarket lasagne in the
oven/convection mode instead of microwave mode.

I have done it only once before... but with a different kind of lasagne
lol..

I hope the black bucket is ok for oven I think so... manual said nothing
about having to replace it in a special thing... hmmm..

Skybuck Flying

unread,
Sep 21, 2015, 2:53:15 PM9/21/15
to
Interesting... amazingly enough... the black plastic didn't melt.

I thought it wouldn't cause in microwave mode the heat can also be pretty
intense...

So oven should survive it too...

I guess it's some new kind of plastic ! ;)

I have seen some of this kind of plastic bending though ! ;)

Bye,
Skybuck.

Skybuck Flying

unread,
Sep 21, 2015, 2:54:20 PM9/21/15
to
Well that was a total fail lol..

It wasnt' heated properly...

Maybe I should have put it on a rack.

Oh well..

I ll just stick with micro over mode for now ! ;)

Bye,
Skybuck :)

Skybuck Flying

unread,
Sep 21, 2015, 2:58:52 PM9/21/15
to
! in C is supposed to be logical not.

Not exactly sure what is ment with that... but to me it would seem this
converts integers to boolean.

So this could be some kind of integer to boolean conversion operator.

Perhaps a typecast to boolean might help for Delphi.

Anyway I also base this on inspecting the assembly a little bit... there was
a cmp in it... which probably sets some flags...

and then some kind of set instruction was executed.

Just for the kick of it here it is:


return ((!!x) | (x >> 31));

010A13AE xor eax,eax

010A13B0 cmp dword ptr [x],0

010A13B4 setne al

010A13B7 mov ecx,dword ptr [x]

010A13BA sar ecx,1Fh

010A13BD or eax,ecx



Bye,

Skybuck.

Skybuck Flying

unread,
Sep 21, 2015, 3:25:09 PM9/21/15
to
This kinda confirms my suspicion:

printf("%d \n", !100); // 0

printf("%d \n", !!100); // 1

printf("%d \n", !-100); // 0

printf("%d \n", !!-100); // 1

The not operator in C apperently can by used to convert a value to a
boolean, just a 0 or a 1.

However it also negates it sort of...

So this makes the double not operator !! kind of a funny way/trick to
convert it back again.

Only problem with it is it stays zero or positive and doesn't turn negative.

I also tested my other suspicion:

printf("%d \n", -8 >> 1); // prints -4

the SAR shift in action here keeps -8 negative when it's shifted down
towards -4.

A SHL would have turned this positive.

So basically a SAR shifts in one's from the most significant bit position
(towards least). * not entirely correct.

So basically a SHL shifts in zero's from the most significant bit position
(towards least).

So basically the C code produces:

(0 or 1) or (Negative).

However since it shifts all the way down to least significant bit, it will
turn into:

(0 or 1) or (0 or -1).

Though I am not exactly sure what happens if X is positive or X is zero when
using SAR.

I would expect:

0 SAR X to produce 0 ? or maybe not... since it will shift in 1's from the
msb side probably...

if true... if it's shift a left shifter with 1's than zero would turn
negative.

I'll test this... if this is not going to happen than the cpu does even more
processing for SAR:

Hmm interestingly enough:

printf("%d \n", 0 >> 1); // produces zero.

So my theory at * is not fully correct. eitherwise 0 should lead
to: -2147483648 probably.

100000000andsoforth0000.

So CPU seems to be doing something extra for SAR.

Anyway this means final conclusion is indeed:

(0 or 1) or (0 or -1).

Not the strange thing is or-ing a positive value with a negative value...
that's kinda weird.

However maybe this final conclusion is wrong ?!

What does SAR 31 actually do ? hmmm...

What does it preserve ?

I would guess the highest significant bit ?

Let's that's that with a max negative value.

-2147483648

printf("%d \n", -2147483648 >> 31); // this leads to 1 as far as I can tell
which is kinda strange...

I'm a bit confused now...

One possibility is that this C function is actually bugged, and might
produce a wrong value for certain ranges.

Funny thing is I don't have a C test program available yet to test out all
ranges.

For now I will have to assume that this function could possibly be bugged !
;)

To the TEST CAVE BATMAN ! ;) =D

This will need to be continued... later... after verifieing is this function
is actually correct in C or if it has problems ?! ;)

TUTUTUTUTUTUTUTUTUTUTUTUTUTUT BATMAN !!!! PAAAAAWWWW !

Bye,

Skybuck.




























Skybuck Flying

unread,
Sep 21, 2015, 3:50:49 PM9/21/15
to
The C function seems to be correct for the full 32 bit signed integer range.

Hmmmmm :)

Bye,
Skybuck.

Skybuck Flying

unread,
Sep 21, 2015, 3:54:20 PM9/21/15
to
It's a little bit bizar how SAR seems to value for:
printf("%d \n", -2147483648 >> 1 );

Why the C function still remains correct is also a bit bizar... maybe
signed/unsigned don't matter hmm...

This is putting me off a bit... hmm..

For now I will have to ignore this issue.

Bye,

Skybuck.

Skybuck Flying

unread,
Sep 21, 2015, 4:02:25 PM9/21/15
to
Ok,

0 or -1 seems to make sense now, since -1 is $FFFFFFFF.

Or simply all bits set.

All bits set or 0 will keep all bits set.

So 0 or negative will remain negative as it was... kinda funny.

But now the last question is:

What happens if 1 or -1 happens ?

1 is written as
00000000000001

-1 is written as
11111111111111

So or-ing this will keep the negative value...

However if it was something like:

00001101010
11110101101

it may create problems... but apperently not... since these values were not
possible...

since ! operator converts them to either 0 or 1.

So only:
1 or -1
needs to be looked at... which keeps -1
So end table/conclusion seems to be:
L = left
R = right
O = or-ed output
L R O
0 0 0
1 0 1
0 1 1
1 1 1
0 -1 -1
1 -1 -1

So !!X basically scales down positives and negative values to either 0 or 1.

Zero to zero
Negative to one
Positive to one

So at least the zero is ok.

However the one has to be either 1 or -1 OR 1 or 1

So the right side examines the negativity of it I think...

If it's indeed negative than the or result will be negative... if it was
positive then it stays positive.

So this basically explains the function...

Hmmm :)

Now only remaining question is how to create this thruth table in Delphi via
operations ?! :) hmm interesting :)

Bye,
Skybuck.

M Philbrook

unread,
Sep 21, 2015, 6:02:38 PM9/21/15
to
In article <1315e$5600499f$d47876e2$34...@news.ziggo.nl>, skybuck2000
@hotmail.com says...
So what do you think (!!x) will do?

I just couldn't help from noticeing.

Jamie


M Philbrook

unread,
Sep 21, 2015, 6:09:07 PM9/21/15
to
In article <f3842$5600536b$d47876e2$45...@news.ziggo.nl>, skybuck2000
@hotmail.com says...
I would like to know why you are using double "!!" ?

That is a "not" operation and does nothing more than
give you the reverse.

Most likely the compiler is ignoring your bad code.

Robert Wessel

unread,
Sep 21, 2015, 6:50:37 PM9/21/15
to
!! is a common C idiom for reducing a zero/non-zero value to zero/one.

James Kuyper

unread,
Sep 21, 2015, 7:15:08 PM9/21/15
to
On 09/21/2015 06:51 PM, Robert Wessel wrote:
> On Mon, 21 Sep 2015 18:15:23 -0400, M Philbrook
> <jamie_...@charter.net> wrote:
>
>> In article <f3842$5600536b$d47876e2$45...@news.ziggo.nl>, skybuck2000
>> @hotmail.com says...
>>>
>>> ! in C is supposed to be logical not.
>>>
>>> Not exactly sure what is ment with that... but to me it would seem this
>>> converts integers to boolean.
>>>
>>> So this could be some kind of integer to boolean conversion operator.
>>>
>>> Perhaps a typecast to boolean might help for Delphi.
>>>
>>> Anyway I also base this on inspecting the assembly a little bit... there was
>>> a cmp in it... which probably sets some flags...
>>>
>>> and then some kind of set instruction was executed.
>>>
>>> Just for the kick of it here it is:
>>>
>>>
>>> return ((!!x) | (x >> 31));
...
>>
>> I would like to know why you are using double "!!" ?
>>
>> That is a "not" operation and does nothing more than
>> give you the reverse.
>>
>> Most likely the compiler is ignoring your bad code.
>
>
> !! is a common C idiom for reducing a zero/non-zero value to zero/one.

Which doesn't seem particularly useful as the left operand of a
bitwise-or operator in this context.

My best guess is that he thought it mapped zero/non-zero to zero/(-1).
For certain unportable assumptions about how x>>31 works for negative
numbers, that would produce the right result. That would require that he
have serious misconceptions about how the unary ! operator works - but
the words above make it pretty clear that he's pretty much clueless
about such things.

M Philbrook

unread,
Sep 21, 2015, 9:59:34 PM9/21/15
to
In article <id210btlsqe47v45g...@4ax.com>, robertwessel2
@yahoo.com says...
> I would like to know why you are using double "!!" ?
> >
> > That is a "not" operation and does nothing more than
> >give you the reverse.
> >
> > Most likely the compiler is ignoring your bad code.
>
>
> !! is a common C idiom for reducing a zero/non-zero value to zero/one.
>
>

Thats strange because I referenced 3 C and C++ books for that before
posting that and there is no information about using double "!!" and
I put a lot of hours into C coding years ago doing the tightest level
code I could get with out doing ASM.

I don't worry much about that tight coding any more, the little
difference between C/C++ over what Delphi or the like can is isn't
worth it any more.

Jamie

Robert Wessel

unread,
Sep 22, 2015, 12:58:46 AM9/22/15
to
That Skybuck is clueless is a given.

But assuming the desired behavior of signed shifts (obviously not
guaranteed by the standard, but a not unlikely result on x86), the
expression will evaluate as 1|-1 for a negative input, 0|0 for zero,
or 1|0 for a positive input. Also assuming twos' complement, those
will result in -1/0/1 for negative/zero/positive inputs.

Obviously Delphi defines something in there differently.

Skybuck Flying

unread,
Sep 22, 2015, 2:31:32 AM9/22/15
to
"
So what do you think (!!x) will do?
"

Mysteries/funny isn't it ?! ;)

I think I already tested and explained it in another postings... but those
full of other thoughts and experiments and conclusions.

So I will sum it up for you one last time:

It seems ! is a sort of integer to boolean convertor, in such a way that it
only produces a 1 or 0. So no higher ranging values.

I am not sure yet but Delphi will accept 123 also as true. So Delphi does
not "truncate" or limit boolean typecasts or not operator to just 0 or 1.

Perhaps that was done to keep execution speed or perhaps it's a bit sloppy
or just the way the language was designed.

I also think Delphi might prevent the usage of SAR since SAR is buggy. It
does not seem to work correctly for maximum negativity for 32 bits, a smart
choice it seems.

!! simply inverts it from X to 0, back to 1
or from X to 1 back to 0.

So it's like not not.

or xor xor or something.

or -- a; Delphi style not c style ;) meaning (-(-a)).

Bye,
Skybuck.


Skybuck Flying

unread,
Sep 22, 2015, 4:18:48 AM9/22/15
to
I though about the theory and rolled my own ! ;) :)

The idea I had was to multiple the input with some kind of number, possibly
a negative number to try and turn positivity into negativity into such a way
that the result of the multiplication
would always be negative or zero.

I was thinking about searching for such a multiplication number and then it
occured to me, I already know a number which I could use to multiply with to
achieve that result... and that is -1.

Positive * -1 = Negative or Zero
Negative * - 1 =Positive or Zero
^ Perhaps that might lead to problems...

Anyway then I though ok... -1 is problably same as negation -Para.

Then tested it... this function almost works.

it has a problem with -2147483648
function IntegerSignV2( Para : integer ) : integer;
begin
// result := ((-(Para * (not (Para shr 31)))) shr 31) - (Para shr 31);

// step 1, original idea
// result := integer(Para > 0) - integer(Para < 0);

// step 2, removing is negative or zero branch:
// result := integer(Para > 0) - (Para shr 31);

// step 3, removing is positive or zero branch
result := ((-Para) shr 31) - (Para shr 31);
end;

Perhaps it can be solved by multiplieing Para with something else than -1.

Bye,
Skybuck.

Skybuck Flying

unread,
Sep 22, 2015, 4:50:24 AM9/22/15
to
One possible idea/solution is to ignore the zero case and still include
it/solve it as follows:

The solution to including checking for zero would be to assume that the
input is zero.

Thus we write zero to the output as in my original/bestly suited solution
for constrain:

Output := Input;

then we only need to check for negativity and check for positivity.

Thus we assume the input is always zero and thus output it.

And we only need to overwrite output if it was something different:

Output := Input;
if Input < 0 then Output := -1;
if Output > 0 then Output := 1;

However zero-fieing is doable... but detection zero is not.

So instead of writing input to output we might as well write:

Output := 0;
if Input < 0 then Output := -1;
if Output > 0 then Output := 1;

Now the question is how can be incorporate the negative detection and
positive the detection.

The negative detection will also produce a 0 or -1... we don't want to
overwrite 0 with 0, only with -1.

However negative detection returns 1 for zero as well, there lies the
problem.

Can we invert zero to somehow negate something else, probably not, or maybe
there is a way:

not 0 might turn out to be 1.

So perhaps Delphi offers away to produce just a 1 if it's zero.

However... the input might be something else than zero..
Not X might produce something tottaly different than 1.
That is indeed the unfortunate case ;)

Is there any operation in Delphi that can truncate a value to either -1 or 1
? without requiring many instructions or branches ?!?

Not something I can known of immediatly... there might be something
though... not sure...

If not than that quite an omission in Delphi it seems ! ;) :)

And thus we might be stuck/doomed ! =D

And might never get a good solution for this.

Unless we can perhaps detect just negativity and just positivity without
including a 1 in the output for zero.

Can we detect positivity in such a way that it only produces a 1 for
positive ? No... but would the zero be a problem ?

No...

So perhaps detecting positivity is usuable:

IsPositive: not (Input shr 31)

this will convert 1 = negative to 0 = positive.
this will convert 0 = zero to 1 = zero.

So perhaps by inverting it again we can finally get a good positivity
detector:

not not (Input shr 31)

1 = positive
0 = zero

Let's try that:

function IsPositive( Para : integer ) : integer;
begin
result := not not (Para shr 31);
end;

// ^ doesn't work for zero.

However there is still some hope, somehow... very maybe:

writeln( integer( not True) ); // produces 0
writeln( integer( not False) ); // produces 1

writeln( integer( not 1) ); // produces -2
writeln( integer( not 0) ); // produces -1

^ Kinda funny.

Bye,
Skybuck.

Skybuck Flying

unread,
Sep 22, 2015, 5:00:14 AM9/22/15
to
writeln( integer( not True) ); // produces 0
writeln( integer( not False) ); // produces 1

writeln( integer( not 1) ); // produces -2
writeln( integer( not 0) ); // produces -1

// ^ Kinda funny :)

// let's see if we can use this theory to produce a 0 or 1 for any given
value
// just like C's not. cause that's the problem... we don't know how to do
that in Delphi
// so know we may have learned it ! ;) =D

// let's assume we have some large positive value, inverting this should
produce a 0.
// let's assume we have some large negative value, inverting this should
produce a 1
// let's assume we have a zero, inverting this should produce a 1
// let's assume we have a one, inverting this should produce a 0

// so tests:
writeln( integer( not boolean(123) ) ); // should produce a 0, actually
produces a 0
writeln( integer( not boolean(-123) ) ); // should produce a 0, actually
produces a 0

writeln( integer( not not boolean(123) ) ); // should produce a 1, actually
produces a 1
writeln( integer( not not boolean(-123) ) ); // should produce a 1, actually
produces a 1

writeln( integer( not boolean(0) ) ); // should produce a 1, actually
produces a 1

// ^ problem solved ! by using typecasts correctly we should be able to
solve this problem in Delphi ! ;) =D

Bye,
Skybuck.

Skybuck Flying

unread,
Sep 22, 2015, 5:07:03 AM9/22/15
to
It's still not working correctly though:

function IntegerSignV3( Para : integer ) : integer;
begin
result := (integer(not not boolean(Para)) - integer(int64(Para) shr 32) );
end;

function IntegerSignV3( Para : integer ) : integer;
begin
result := (integer(not not boolean(Para)) or integer(int64(Para) shr 32) );
end;

The int64 is a sar trick... sign extended and then shifting it down by 32.

"sign extended and shift it down" something like that.

Mysterious ;)

Bye,
Skybuck.

Skybuck Flying

unread,
Sep 22, 2015, 5:15:30 AM9/22/15
to
Delphi is doing something very strange as soon as variables are typecasted
to booleans.

It does not produce the same results as the writeln stuff...

Perhaps it's a bug... or a very nasty inconsistency .

Very strange

Bye,
Skybuck.

Skybuck Flying

unread,
Sep 22, 2015, 5:20:24 AM9/22/15
to
Weird behaviour of Delphi explained, it seems the compiler optimized the
constants away !

This is actually quite nasty behaviour of the compiler, and very
inconsistent ?! ;)

Perhaps somebody should file a bug report ?! ;)

Why would one allow Delphi to optimize constants like this ?!

While in reality if a variable was used the behaviour would have been
different ?!

This will definetly confuse programmers like me... and creates an
inconsistent view in the way Delphi behaves during typecasts !

I don't like this constant optimization for this obvious reason ! It
deceived/confused me !

Bad bitch !

procedure Example;
var
x : integer;
begin
// so tests:
x := 123;
writeln( integer( not boolean(x) ) ); // should produce a 0, actually
produces a 122

x := -123;
writeln( integer( not boolean(-x) ) ); // should produce a 0, actually
produces a 122

x := 123;
writeln( integer( not not boolean(x) ) ); // should produce a 1, actually
produces a 123

x := -123;
writeln( integer( not not boolean(x) ) ); // should produce a 1, actually
produces a 5

x := 0;
writeln( integer( not boolean(x) ) ); // should produce a 1, actually
produces a 1

end;

procedure Main;
var
vIndex : integer;
begin

writeln( integer( not True) ); // produces 0
writeln( integer( not False) ); // produces 1

writeln( integer( not 1) ); // produces -2
writeln( integer( not 0) ); // produces -1

// it was just an illusion lol ! ;) Delphi probably optimized the constants
above ! ;) :)
writeln('example');
Example;
writeln('example');

Bye,
Skybuck.

Skybuck Flying

unread,
Sep 22, 2015, 5:23:01 AM9/22/15
to
The constants in the boolean typecasts were converted/optimized to just
one's and zero's so it was misleading !

Nasty behaviour of Delphi (compiler) ! ;)

Bye,
Skybuck.

James Kuyper

unread,
Sep 22, 2015, 10:17:10 AM9/22/15
to
On 09/21/2015 10:06 PM, M Philbrook wrote:
> In article <id210btlsqe47v45g...@4ax.com>, robertwessel2
...
>> !! is a common C idiom for reducing a zero/non-zero value to zero/one.
>>
>>
>
> Thats strange because I referenced 3 C and C++ books for that before
> posting that and there is no information about using double "!!" and
> I put a lot of hours into C coding years ago doing the tightest level
> code I could get with out doing ASM.

Hint: !! is not a single operator, it's two separate ! operators. !!x
means the same thing as !(!x). Does that make it any clearer?
--
James Kuyper

M Philbrook

unread,
Sep 22, 2015, 7:42:11 PM9/22/15
to
In article <mtrnph$6qg$1...@dont-email.me>, james...@verizon.net says...
People like you make me smile, even chunkle once in a while.


Jamie

0 new messages