Jump to page: 1 2
Thread overview
Problem with object understanding and datatypes
May 24, 2013
Namal
May 24, 2013
Ali Çehreli
May 25, 2013
Namal
May 25, 2013
Juan Manuel Cabo
May 25, 2013
Namal
May 25, 2013
bearophile
May 25, 2013
Namal
May 25, 2013
Ali Çehreli
May 25, 2013
Namal
May 25, 2013
Namal
May 25, 2013
Ali Çehreli
Jun 23, 2013
Nordlöw
May 24, 2013
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
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 25, 2013
> 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 25, 2013
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 25, 2013
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
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
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
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
Thanks, that helped me alot.
May 25, 2013
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.
« First   ‹ Prev
1 2