www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Strange behaviour trying to bitwise or two negative ints into a long

reply Deewiant <deewiant.doesnotlike.spam gmail.com> writes:
import std.stdio;

int a = -1;
int b = -2;

void main() {
	writefln("       a: 0b%064b", a);
	writefln("       b: 0b%064b", cast(long)b);
	writefln(" b << 32: 0b%064b", cast(long)b << 32);
	writefln("| a     : 0b%064b", cast(long)b << 32 | a);
	writefln("| a &   : 0b%064b", cast(long)b << 32 | (a & 0xffff_ffff));
	writefln("| cast a: 0b%064b", cast(long)b << 32 | cast(uint)a);

	/+ using values copied from the outputs of the first two writeflns above +/
	writefln("binconst: 0b%064b",
0b1111111111111111111111111111111111111111111111111111111111111110 << 32 |
0b0000000000000000000000000000000011111111111111111111111111111111);
}

Why do the last writeflns output a different number than the plain cast(long)b
<< 32 | a one? Why do I need the cast or bitwise and?

I was originally going to file a bug but I think I'm just misunderstanding
something fundamental.

-- 
Remove ".doesnotlike.spam" from the mail address.
May 11 2007
parent reply Thomas Kuehne <thomas-dloop kuehne.cn> writes:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Deewiant schrieb am 2007-05-11:
 import std.stdio;

 int a = -1;
 int b = -2;

 void main() {
 	writefln("       a: 0b%064b", a);
 	writefln("       b: 0b%064b", cast(long)b);
 	writefln(" b << 32: 0b%064b", cast(long)b << 32);
 	writefln("| a     : 0b%064b", cast(long)b << 32 | a);
 	writefln("| a &   : 0b%064b", cast(long)b << 32 | (a & 0xffff_ffff));
 	writefln("| cast a: 0b%064b", cast(long)b << 32 | cast(uint)a);

 	/+ using values copied from the outputs of the first two writeflns above +/
 	writefln("binconst: 0b%064b",
 0b1111111111111111111111111111111111111111111111111111111111111110 << 32 |
 0b0000000000000000000000000000000011111111111111111111111111111111);
 }

 Why do the last writeflns output a different number than the plain cast(long)b
<< 32 | a one? Why do I need the cast or bitwise and?

 I was originally going to file a bug but I think I'm just misunderstanding
 something fundamental.

There is a bug as well as a misunderstanding. # import std.stdio; # # int thirty_one = 31; # int thirty_two = 32; # int thirty_three = 33; # int two_neg = -2; # int four_neg = -4; # int i = -1; # uint u = -1; # # TypeInfo type_info(...){ # return _arguments[0]; # } # void info(char[] exp)(char[] comment = null){ # writef("0b%064b ", mixin(exp)); # writef("%s", typeof(mixin(exp)).stringof); # mixin("writefln(\"\t%s\", \"" ~ exp ~ "\");"); # if(comment.length){ # writefln("\t%s", comment); # } # } # # void main() { # info!("i"); # info!("u"); # info!("two_neg"); # writefln(); # info!("cast(long)two_neg << 32 | i"); # info!("cast(long)two_neg << 32 | u")("Why do they differ?"); # writefln(); # info!("two_neg << 32")("Huh? Let's try that again:"); # info!("two_neg"); # info!("two_neg << thirty_two"); # info!("(two_neg << 31) << 1"); # info!("(two_neg << 31) << 2"); # info!("two_neg << thirty_three"); # writefln(); # writefln("%s", "issue: shifting is implemented as\n" # "\t\tx << (shift % (sizeof(x) * 8))\n" # "\tinstead of\n" # "\t\tx << ((shift >= (sizeof(x) * 8)) ? (0) : (shift))"); # writefln("at least for cases where the shift width is known at compile time accepting \"sizeof(x) * 8\" is a bug"); # writefln(); # writefln("Let's try another approach:"); # info!("cast(long)two_neg << 32 | i"); # info!("cast(long)two_neg << 32 | u"); # info!("(cast(long)two_neg) << 32 | i"); # info!("(cast(long)two_neg) << 32 | u"); # info!("((cast(long)two_neg) << 32) | i"); # info!("((cast(long)two_neg) << 32) | u"); # info!("((cast(long)two_neg) << 32) | (cast(long)i)"); # info!("((cast(long)two_neg) << 32) | (cast(long)u)"); # info!("((cast(long)two_neg) << 32) | (cast(long)i)"); # info!("((cast(long)two_neg) << 32) | (cast(long)u)"); # writefln(); # info!("(cast(long)two_neg) << 32"); # info!("cast(long) 0xFFFFFFFE_00000000L"); # info!("(cast(long) 0xFFFFFFFE_00000000L) | i"); # info!("(cast(long) 0xFFFFFFFE_00000000L) | u"); # info!("cast(long) i"); # info!("cast(long) u"); # writefln(); # writefln("I hope the 2 lines below make sense now"); # info!("cast(long)two_neg << 32 | i"); # info!("cast(long)two_neg << 32 | u"); # } # Thomas -----BEGIN PGP SIGNATURE----- iD8DBQFGRPj7LK5blCcjpWoRAllcAJ9Hk6eFxiqmxcrpLmjeFwqSy0+P9ACbBWUR zWVUdAXJdn1VJFkdf5B7q4o= =if/F -----END PGP SIGNATURE-----
May 11 2007
parent Deewiant <deewiant.doesnotlike.spam gmail.com> writes:
Thomas Kuehne wrote:
 Deewiant schrieb am 2007-05-11:
 import std.stdio;

 int a = -1;
 int b = -2;

 void main() {
 	writefln("       a: 0b%064b", a);
 	writefln("       b: 0b%064b", cast(long)b);
 	writefln(" b << 32: 0b%064b", cast(long)b << 32);
 	writefln("| a     : 0b%064b", cast(long)b << 32 | a);
 	writefln("| a &   : 0b%064b", cast(long)b << 32 | (a & 0xffff_ffff));
 	writefln("| cast a: 0b%064b", cast(long)b << 32 | cast(uint)a);

 	/+ using values copied from the outputs of the first two writeflns above +/
 	writefln("binconst: 0b%064b",
 0b1111111111111111111111111111111111111111111111111111111111111110 << 32 |
 0b0000000000000000000000000000000011111111111111111111111111111111);
 }

 Why do the last writeflns output a different number than the plain cast(long)b
 << 32 | a one? Why do I need the cast or bitwise and?

 I was originally going to file a bug but I think I'm just misunderstanding
 something fundamental.

There is a bug as well as a misunderstanding. # import std.stdio; # # int thirty_one = 31; # int thirty_two = 32; # int thirty_three = 33; # int two_neg = -2; # int four_neg = -4; # int i = -1; # uint u = -1; # # TypeInfo type_info(...){ # return _arguments[0]; # } # void info(char[] exp)(char[] comment = null){ # writef("0b%064b ", mixin(exp)); # writef("%s", typeof(mixin(exp)).stringof); # mixin("writefln(\"\t%s\", \"" ~ exp ~ "\");"); # if(comment.length){ # writefln("\t%s", comment); # } # } # # void main() { # info!("i"); # info!("u"); # info!("two_neg"); # writefln(); # info!("cast(long)two_neg << 32 | i"); # info!("cast(long)two_neg << 32 | u")("Why do they differ?"); # writefln(); # info!("two_neg << 32")("Huh? Let's try that again:"); # info!("two_neg"); # info!("two_neg << thirty_two"); # info!("(two_neg << 31) << 1"); # info!("(two_neg << 31) << 2"); # info!("two_neg << thirty_three"); # writefln(); # writefln("%s", "issue: shifting is implemented as\n" # "\t\tx << (shift % (sizeof(x) * 8))\n" # "\tinstead of\n" # "\t\tx << ((shift >= (sizeof(x) * 8)) ? (0) : (shift))"); # writefln("at least for cases where the shift width is known at compile time accepting \"sizeof(x) * 8\" is a bug"); # writefln(); # writefln("Let's try another approach:"); # info!("cast(long)two_neg << 32 | i"); # info!("cast(long)two_neg << 32 | u"); # info!("(cast(long)two_neg) << 32 | i"); # info!("(cast(long)two_neg) << 32 | u"); # info!("((cast(long)two_neg) << 32) | i"); # info!("((cast(long)two_neg) << 32) | u"); # info!("((cast(long)two_neg) << 32) | (cast(long)i)"); # info!("((cast(long)two_neg) << 32) | (cast(long)u)"); # info!("((cast(long)two_neg) << 32) | (cast(long)i)"); # info!("((cast(long)two_neg) << 32) | (cast(long)u)"); # writefln(); # info!("(cast(long)two_neg) << 32"); # info!("cast(long) 0xFFFFFFFE_00000000L"); # info!("(cast(long) 0xFFFFFFFE_00000000L) | i"); # info!("(cast(long) 0xFFFFFFFE_00000000L) | u"); # info!("cast(long) i"); # info!("cast(long) u"); # writefln(); # writefln("I hope the 2 lines below make sense now"); # info!("cast(long)two_neg << 32 | i"); # info!("cast(long)two_neg << 32 | u"); # }

Thanks for this, that clarifies it for me. Added a note to Bug 550. -- Remove ".doesnotlike.spam" from the mail address.
May 12 2007