www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Problem with object understanding and datatypes

reply "Namal" <sotis22 mail.ru> writes:
So the task is to write a struct  object for the saturation 
arithmetic. I tried first to write it for the unsigned Types:

struct Saturated(T)
	if (isIntegral!T)
{
	static assert (isUnsigned!T || isSigned!T);

	 property
	{
		static Saturated min() { return Saturated(T.min); }
		static Saturated max() { return Saturated(T.max); }
		static Saturated init() { return Saturated(T.init); }
	}
	Saturated opBinary(string op)(const Saturated rhs) const
		if (op == "+" || op == "-" || op == "/")
	{
		static if (isUnsigned!T){
			if(rhs.max - rhs._value < _value)
				return rhs.max;
			if(rhs._value > _value)
				return rhs.min;
			return Saturated(cast(T)(mixin("_value " ~ op ~ " 
rhs._value")));
		}
		else{
		return Saturated(cast(T)(mixin("_value " ~ op ~ " 
rhs._value")));
		}
	}

	string toString() const
	{
		import std.conv;
		return to!string(_value);
	}

private:
	T _value;
}

unittest
{
	alias subyte = Saturated!ubyte;
	assert(subyte(254) + subyte(2) == subyte(255));
	assert(subyte(100) + subyte(2) == subyte(102));
	assert(subyte(10) - subyte(11) == subyte(0));
	assert(subyte(128) - subyte(129) == subyte(0));
}

But the last test does not pass. Why does the minus operation is 
treated in signed datatype, while + is unsigned? Note that I do 
not know much about templates or methods. So pls execuse me if I 
do a major mistake here.
May 24 2013
next sibling parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 05/24/2013 01:19 PM, Namal wrote:

              if(rhs.max - rhs._value < _value)
I had a compilation error so I had to change that line to the following: if(T.max - rhs._value < _value){
      assert(subyte(128) - subyte(129) == subyte(0));
 }

 But the last test does not pass.
255 - 129 is less than 128 so the result is T.max, which is 255, which is not equal to 0.
 Why does the minus operation is treated in signed datatype, while + is
 unsigned?
I don't think that is happening at all but the rules can get pretty confusing. See "Integer Promotions" and "Usual Arithmetic Conversions" should be known in general: :) http://dlang.org/type.html Ali
May 24 2013
parent reply "Namal" <sotis22 mail.ru> writes:
 255 - 129 is less than 128 so the result is T.max, which is 
 255, which is not equal to 0.
I dont understand this at all 255 - 129 should be 126 in ubyte or not?
May 24 2013
parent reply "Juan Manuel Cabo" <juanmanuel.cabo gmail.com> writes:
On Saturday, 25 May 2013 at 01:03:53 UTC, Namal wrote:
 255 - 129 is less than 128 so the result is T.max, which is 
 255, which is not equal to 0.
I dont understand this at all 255 - 129 should be 126 in ubyte or not?
I checked, and operation between two ubyte is an int. When you cast that int to ubyte, it gets its least significant byte represented as ubyte. import std.stdio; void main() { ubyte x = 128; ubyte y = 129; writeln(cast(ubyte)(x - y)); //prints 255 writeln(x - y); //prints -1 writeln(typeof(x - y).stringof); //prints 'int' !!!! } Also, I tried the code you pasted, and the reason it fails the asserts is that there's something wrong in the if conditions in opBinary (and also, that 'rhs.max - rhs._value' didn't compile). The following makes your asserts pass: ... static if (op == "-") { if(_value < rhs._value) return rhs.min; } static if (op == "+") { if(_value > max._value - rhs._value) return rhs.max; } ... --jm
May 24 2013
parent reply "Namal" <sotis22 mail.ru> writes:
Thank you very much, I thought the operators are alrdy checked by
if (op == "+" || op == "-" || op == "/")

But I did same tests for ushort uint and ulong, but for ulong it 
didn't  compile.

unittest{
	alias sulong = Saturated!ulong;
	assert(sulong(18_446_744_073_709_551_610) + sulong(2) == 
sulong(18_446_744_073_709_551_612));
	assert(sulong(18_446_744_073_709_551_614) + sulong(2) == 
sulong(18_446_744_073_709_551_615));

It failed to compile

Error: signed integer overflow

So I appended uL to each number and it worked.

assert(sulong(18_446_744_073_709_551_610uL) + sulong(2uL) == 
sulong(18_446_744_073_709_551_612uL));

Was it the right idea to fix it? And if so, do I always have to 
use a suffix when the number is bigger than  uint?
May 25 2013
parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Namal:

 And if so, do I always have to use a suffix when the number is 
 bigger than  uint?
It looks a bit silly, I agree. Bye, bearophile
May 25 2013
parent reply "Namal" <sotis22 mail.ru> writes:
On Saturday, 25 May 2013 at 10:15:42 UTC, bearophile wrote:
 Namal:

 And if so, do I always have to use a suffix when the number is 
 bigger than  uint?
It looks a bit silly, I agree. Bye, bearophile
Well, now I have same Error for signed long: else{ static if (op == "+"){ if(rhs._value > T.init && T.max - rhs._value < _value) return rhs.max; else if(rhs._value < T.init && T.min - rhs._value > _value) return rhs.min; } static if (op == "-"){ if(rhs._value > T.init && T.min+rhs._value > _value) return rhs.min; else if(rhs._value < T.init && T.max + rhs._value < _value) return rhs.max; } static if (op == "/"){ if(rhs._value == -1) return rhs.max; } does work for every type exept long. Like for the addition unittest{ alias slong = Saturated!long; assert(slong(9_223_372_036_854_775_806) + slong(2) == slong(9_223_372_036_854_775_807)); assert(slong(9_223_372_036_854_775_806) + slong(-3) == slong(-9_223_372_036_854_775_808)); } The first test is ok, but second wont even compile. Even if I append a L to each number.
May 25 2013
parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 05/25/2013 04:34 AM, Namal wrote:

      assert(slong(9_223_372_036_854_775_806) + slong(-3) ==
 slong(-9_223_372_036_854_775_808));
 }

 The first test is ok, but second wont even compile. Even if I append a L
 to each number.
According to the "Integer Literals" section here: http://dlang.org/lex.html Decimal literals are resolved as either int or long. 9_223_372_036_854_775_808 cannot fit either of those types. If you want ulong, you must either write the literal in hexadecimal or binary format or provide the UL suffix. Ali
May 25 2013
parent reply "Namal" <sotis22 mail.ru> writes:
Thanks, that helped me alot.
May 25 2013
parent reply "Namal" <sotis22 mail.ru> writes:
I have one more question towards using unsigned datatype

   assert(sint(-2_147_483_647) - sint(3) == sint(-2_147_483_648));
   assert(sint(-2_147_483_647) - sint(3) == sint(2_147_483_648));

Here I get an error for the second line, because it cannot be 
convertet

if i use unsigned

   assert(sint(-2_147_483_647) - sint(3) == sint(-2_147_483_648));
   assert(sint(-2_147_483_647) - sint(3) == sint(2_147_483_648u));

it makes no difference and I get an error. Why doesn't the minus 
sign matter here and how do I fix this? Especially where I have 
to use u

   assert(slong(-9_223_372_036_854_775_807) - slong(2) == 
slong(-9_223_372_036_854_775_808u));
   assert(slong(-9_223_372_036_854_775_807) - slong(2) == 
slong(9_223_372_036_854_775_808u));

Also tried this with hex numbers but it is same with them.
May 25 2013
parent =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 05/25/2013 11:57 AM, Namal wrote:

 I have one more question towards using unsigned datatype

    assert(sint(-2_147_483_647) - sint(3) == sint(-2_147_483_648));
    assert(sint(-2_147_483_647) - sint(3) == sint(2_147_483_648));

 Here I get an error for the second line, because it cannot be convertet
It helps a lot if you tell the error message. After making some assumption I was able to produce an error message: Error: cannot implicitly convert expression (2147483648L) of type long to int It makes sense if sint is Saturated!int. 2147483648 is long but the struct member is int.
 if i use unsigned

    assert(sint(-2_147_483_647) - sint(3) == sint(-2_147_483_648));
    assert(sint(-2_147_483_647) - sint(3) == sint(2_147_483_648u));

 it makes no difference and I get an error.
This time 2_147_483_648u is a uint which happens to have automatic conversion to int. Automatic type conversions can be extremely confusing. Let's see... import std.stdio; struct S { int i; } void main() { // uint converts to int: auto s = S(1u); int i; uint u = uint.max; // same: i = u; // Surprising result: assert(i == -1); } These rules are both because they are same or similar in C and also for convenience. But yes, they can be confusing... Ali
May 25 2013
prev sibling parent =?UTF-8?B?Ik5vcmRsw7Z3Ig==?= <per.nordlow gmail.com> writes:
Is this code available in any repo/archive somewhere?

/Per
Jun 23 2013