www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Possible unsigned float type?

reply "Garett Bass" <garettbass studiotekne.com> writes:
I would really like to have an unsigned float type for a project I'm working 
on.  Some measurements, such as width, height, just don't make any sense if 
they are allowed to be negative, and no one wants to write checks or clamps 
all over the place to deal with it.

In C++ I created a set of pseudonumeric classes that overloaded all of the 
math operators to allow me to easily perform the usual routines on my 
"unsigned float" values.  However, such classes never really interact quite 
right with native types, and I ended up using operator ( ) to quickly 
retrieve the actual float value when I needed to mix it up with built-in 
data types.

Overall, this is sloppy and unfortunate.  Is it possible to create 
pseudonumeric classes in D that interact normally with other built-ins 
without casting or ( )'ing all the time?  Would it be difficult to 
incorporate an unsigned float built-in type?

Regards,
Garett 
Oct 31 2005
next sibling parent "Regan Heath" <regan netwin.co.nz> writes:
On Mon, 31 Oct 2005 23:02:53 -0600, Garett Bass  
<garettbass studiotekne.com> wrote:
 I would really like to have an unsigned float type for a project I'm  
 working
 on.  Some measurements, such as width, height, just don't make any sense  
 if
 they are allowed to be negative, and no one wants to write checks or  
 clamps
 all over the place to deal with it.

 In C++ I created a set of pseudonumeric classes that overloaded all of  
 the
 math operators to allow me to easily perform the usual routines on my
 "unsigned float" values.  However, such classes never really interact  
 quite
 right with native types, and I ended up using operator ( ) to quickly
 retrieve the actual float value when I needed to mix it up with built-in
 data types.

 Overall, this is sloppy and unfortunate.  Is it possible to create
 pseudonumeric classes in D that interact normally with other built-ins
 without casting or ( )'ing all the time?  Would it be difficult to
 incorporate an unsigned float built-in type?
A while back Arcane Jill wrote a big integer class which had similar problems. Her work can be found here: http://svn.dsource.org/projects/deimos/trunk/etc/ Might be useful/interesting maybe. Regan
Nov 01 2005
prev sibling next sibling parent =?ISO-8859-1?Q?Jari-Matti_M=E4kel=E4?= <jmjmak invalid_utu.fi> writes:
Garett Bass wrote:
 I would really like to have an unsigned float type for a project I'm working 
 on.  Some measurements, such as width, height, just don't make any sense if 
 they are allowed to be negative, and no one wants to write checks or clamps 
 all over the place to deal with it.
IMHO even if you could use unsigned types, you should always explicitly check all input values. Is it better to let variables overflow? If you don't need more than 80 bits of precision, it might be too heavy a choice to use a bigint-library. An alternative would be to create a lightweight float class of your own. D doesn't support assignment overloading, for a good reason though :)
Nov 01 2005
prev sibling parent reply Don Clugston <dac nospam.com.au> writes:
I'd like to challenge the underlying concept here.

You do *not* want an "unsigned float". You want a "positive float".
These two concepts are fundamentally different.
Similarly, I often see code that uses 'unsigned int' or 'uint' when a 
positive int is desired.

An unsigned int is not a positive int. It's an integer with no sign.
I can think of two legitimate applications:
(a) as the lower-order bits in a multi-byte integer. Note that there
  really is no sign. It's not an integer, just part of one.
(b) When you need to squeeze an extra bit of resolution into an 
int/short/etc. This was very common in the 8-bit and 16-bit days,
rarely necessary any more except for cases like size_t.

positive int: range from 0..int.max
unsigned int: range from 0..2*int.max.

 From the CPU's point of view, the difference is evident when multiplying.

Neither of this cases apply to floats.

Using a uint for a value which is only ever in the range 0..int.max is 
IMHO an abuse of the 'unsigned' concept. Especially since the only thing
the compiler does to enforce it is to prevent a direct assignment from a 
literal. Unfortunately, it's an extremely common abuse, with the primary 
effect of causing 'unsigned/signed mismatch' warning in C-style languages.

So, what do we really want?
In some of the Pascal-like languages, you can specify a range for an 
integer as being (say) -2 .. 56.
I think that what you really want is some way of defining a
type (eg PositiveDouble) which is identical to the built-in type 
(double) in Release mode, but at debugging includes a user-specified
class invariant. In this case
assert(isnan(this) || this>=0.0);

This would be far more powerful than the Pascal range concept, because 
you could
limit it to (say) positive ints, or prime numbers, ...

-Don.

Garett Bass wrote:
 I would really like to have an unsigned float type for a project I'm working 
 on.  Some measurements, such as width, height, just don't make any sense if 
 they are allowed to be negative, and no one wants to write checks or clamps 
 all over the place to deal with it.
 
 In C++ I created a set of pseudonumeric classes that overloaded all of the 
 math operators to allow me to easily perform the usual routines on my 
 "unsigned float" values.  However, such classes never really interact quite 
 right with native types, and I ended up using operator ( ) to quickly 
 retrieve the actual float value when I needed to mix it up with built-in 
 data types.
 
 Overall, this is sloppy and unfortunate.  Is it possible to create 
 pseudonumeric classes in D that interact normally with other built-ins 
 without casting or ( )'ing all the time?  Would it be difficult to 
 incorporate an unsigned float built-in type?
 
 Regards,
 Garett 
 
 
Nov 02 2005
next sibling parent kris <fu bar.org> writes:
Right on.


Don Clugston wrote:
 I'd like to challenge the underlying concept here.
 
 You do *not* want an "unsigned float". You want a "positive float".
 These two concepts are fundamentally different.
 Similarly, I often see code that uses 'unsigned int' or 'uint' when a 
 positive int is desired.
 
 An unsigned int is not a positive int. It's an integer with no sign.
 I can think of two legitimate applications:
 (a) as the lower-order bits in a multi-byte integer. Note that there
  really is no sign. It's not an integer, just part of one.
 (b) When you need to squeeze an extra bit of resolution into an 
 int/short/etc. This was very common in the 8-bit and 16-bit days,
 rarely necessary any more except for cases like size_t.
 
 positive int: range from 0..int.max
 unsigned int: range from 0..2*int.max.
 
  From the CPU's point of view, the difference is evident when multiplying.
 
 Neither of this cases apply to floats.
 
 Using a uint for a value which is only ever in the range 0..int.max is 
 IMHO an abuse of the 'unsigned' concept. Especially since the only thing
 the compiler does to enforce it is to prevent a direct assignment from a 
 literal. Unfortunately, it's an extremely common abuse, with the primary 
 effect of causing 'unsigned/signed mismatch' warning in C-style languages.
 
 So, what do we really want?
 In some of the Pascal-like languages, you can specify a range for an 
 integer as being (say) -2 .. 56.
 I think that what you really want is some way of defining a
 type (eg PositiveDouble) which is identical to the built-in type 
 (double) in Release mode, but at debugging includes a user-specified
 class invariant. In this case
 assert(isnan(this) || this>=0.0);
 
 This would be far more powerful than the Pascal range concept, because 
 you could
 limit it to (say) positive ints, or prime numbers, ...
 
 -Don.
 
 Garett Bass wrote:
 
 I would really like to have an unsigned float type for a project I'm 
 working on.  Some measurements, such as width, height, just don't make 
 any sense if they are allowed to be negative, and no one wants to 
 write checks or clamps all over the place to deal with it.

 In C++ I created a set of pseudonumeric classes that overloaded all of 
 the math operators to allow me to easily perform the usual routines on 
 my "unsigned float" values.  However, such classes never really 
 interact quite right with native types, and I ended up using operator 
 ( ) to quickly retrieve the actual float value when I needed to mix it 
 up with built-in data types.

 Overall, this is sloppy and unfortunate.  Is it possible to create 
 pseudonumeric classes in D that interact normally with other built-ins 
 without casting or ( )'ing all the time?  Would it be difficult to 
 incorporate an unsigned float built-in type?

 Regards,
 Garett
Nov 02 2005
prev sibling next sibling parent reply "Garett Bass" <garettbass studiotekne.com> writes:
I beg to differ, I do not want a "positive float".  I want to represent an
absolute floating point value, in the range 
[0..float.max].  It is my understanding that zero is neither a positive nor
negative value.  So, if you disagree with the 
application of the commonly used term "unsigned" to this case, then I should
perhaps be requesting a "non-negative float" ;)

However, unsigned float does seem an appropriate name as it would be the
floating-point equivalent of an unsigned int.

Regards,
Garett 
Nov 02 2005
next sibling parent reply "Garett Bass" <garettbass studiotekne.com> writes:
To clarify, I'm suggesting an IEEE floating point value where the sign bit is
always guaranteed positive, hence float.max, not 2 * 
float.max, but I still argue that zero is a non-positive value, regardless of
the sign bit representation.

"Garett Bass" <garettbass studiotekne.com> wrote in message
news:dkb7g9$et6$1 digitaldaemon.com...
I beg to differ, I do not want a "positive float".  I want to represent an
absolute floating point value, in the range 
[0..float.max].  It is my understanding that zero is neither a positive nor
negative value.  So, if you disagree with the 
application of the commonly used term "unsigned" to this case, then I should
perhaps be requesting a "non-negative float" ;)

 However, unsigned float does seem an appropriate name as it would be the
floating-point equivalent of an unsigned int.

 Regards,
 Garett
 
Nov 02 2005
parent reply =?ISO-8859-1?Q?Jari-Matti_M=E4kel=E4?= <jmjmak invalid_utu.fi> writes:
Garett Bass wrote:
 To clarify, I'm suggesting an IEEE floating point value where the sign bit is
always guaranteed positive, hence float.max, not 2 * 
 float.max, but I still argue that zero is a non-positive value, regardless of
the sign bit representation.
 
 "Garett Bass" <garettbass studiotekne.com> wrote in message
news:dkb7g9$et6$1 digitaldaemon.com...
 
I beg to differ, I do not want a "positive float".  I want to represent an
absolute floating point value, in the range 
[0..float.max].  It is my understanding that zero is neither a positive nor
negative value.  So, if you disagree with the 
application of the commonly used term "unsigned" to this case, then I should
perhaps be requesting a "non-negative float" ;)

However, unsigned float does seem an appropriate name as it would be the
floating-point equivalent of an unsigned int.

Regards,
Garett
In mathematics, the signum has three different values [1]. Surely you do understand that one sign bit can represent only two states and two bits have one state too much. Therefore we have negative and positive values of 0 (two's complement actually has only positive 0). Please explain, what should happen if I would like to do the following: ufloat a = 0; // ufloat = the new "unsigned float" type a--; // what happens now? a = ufloat.max; a++; // what about now? If you're building a purely mathematical application, why don't you just build a custom class for numerical values? It's easy to define arbitrary value ranges using the class invariant. [1] http://en.wikipedia.org/wiki/Sign_function
Nov 02 2005
parent "Garett Bass" <garettbass studiotekne.com> writes:
 If you're building a purely mathematical application, why don't you just build
a custom class for numerical values? It's easy to 
 define arbitrary value ranges using the class invariant.
I don't mind doing this. Part of my original post was a question as to whether psuedonumeric class can interact naturally with the built-in types. I guess what I'd really like to know is whether float opCast() allows implicit conversion to float, or whether explicit conversion is still required. Thanks for the interesting discussion.
Nov 03 2005
prev sibling parent reply Don Clugston <dac nospam.com.au> writes:
OK, perhaps there is less ambiguous word than 'positive'.
Although in IEEE, zero does have a sign. So you want a type where

signbit(x)==0 for all x.
(which is not the same as x >0, because +0.0 is not >0).

But a variable of this type most definitely has a sign; it always lies 
on the real number line in the range [0.. infinity].

This is not true for unsigned ints. An unsigned int genuinely has no 
sign. When you use uint, you are saying,
"The bit representation of this number has no way of expressing the 
sign. I'm taking care of the sign manually in some other way."

It's not the same as saying, "this number is always >=0".
An unsigned number can just as easily represent a number which you know
is always <=0, and where you need the extra bit of resolution.
Or it can be part of a bigint number, where the sign bit is stored 
somewhere else.

Unfortunately, it's extremely common to confuse "no sign" with ">=0".

Again, I really think it would be more useful to be able to apply class 
invariants to built-in types. Then, you could call it "PositiveReal", 
"NonNegativeReal", "ufloat", or anything else.

Maybe with an extension to the typedef syntax; something like:

typedef real invariant { assert(signbit(this)==0); }  NonNegativeReal;

typedef int invariant { assert(this&1==1); } OddInteger;

because I really think your request is a specific instance of a more 
general requirement.


Garett Bass wrote:
 I beg to differ, I do not want a "positive float".  I want to represent an
absolute floating point value, in the range 
 [0..float.max].  It is my understanding that zero is neither a positive nor
negative value.  So, if you disagree with the 
 application of the commonly used term "unsigned" to this case, then I should
perhaps be requesting a "non-negative float" ;)
 
 However, unsigned float does seem an appropriate name as it would be the
floating-point equivalent of an unsigned int.
 
 Regards,
 Garett 
 
 
Nov 03 2005
parent reply Oskar Linde <oskar.lindeREM OVEgmail.com> writes:
In article <dkch0u$1k2o$1 digitaldaemon.com>, Don Clugston says...
Again, I really think it would be more useful to be able to apply class 
invariants to built-in types. Then, you could call it "PositiveReal", 
"NonNegativeReal", "ufloat", or anything else.

Maybe with an extension to the typedef syntax; something like:

typedef real invariant { assert(signbit(this)==0); }  NonNegativeReal;

typedef int invariant { assert(this&1==1); } OddInteger;

because I really think your request is a specific instance of a more 
general requirement.
This would be most useful. Although, I think a higher goal should be to make it possible to define UDT that behave as transparantly as possible as primitive types. With its value based semantics, the D struct is the obvious candidate. It is only lacking the ability to define: - Constructor/destructor (maybe not needed, but very powerful) - Assignment/Copy semantics - Some of the comparison operators (!<>=, etc...) - Implicit casting and promotion (may harm more than help) - anything else? What are the good reasons not to support user defined assignment/copy semantics for structs? One already assumes copying of structs to be a potentially non-trivial operation. The default copy would need to be redefined from a memcpy to memberwise assignment. Making structs more powerful would make it possible to support both the limited range data types you suggest and things like transparent BigNum types, automatic ref-counted resource handles, automatic (and safe) COW types, and more... /Oskar
Nov 03 2005
parent reply Georg Wrede <georg.wrede nospam.org> writes:
Oskar Linde wrote:
 Don Clugston says...
 
 Again, I really think it would be more useful to be able to apply
 class invariants to built-in types. Then, you could call it
 "PositiveReal", "NonNegativeReal", "ufloat", or anything else.
 
 Maybe with an extension to the typedef syntax; something like:
 
 typedef real invariant { assert(signbit(this)==0); }
 NonNegativeReal;
 
 typedef int invariant { assert(this&1==1); } OddInteger;
 
 because I really think your request is a specific instance of a
 more general requirement.
IIRC, this is how it is done in Euphoria. Then we'd have OddInteger (as described above), range types like in Pascal, but also for floats, etc. We could also have coordinate types that allow/disallow a specific area, etc.
 This would be most useful. Although, I think a higher goal should be
 to make it possible to define UDT that behave as transparantly as
 possible as primitive types. With its value based semantics, the D
 struct is the obvious candidate.
 
 It is only lacking the ability to define:
 
 - Constructor/destructor (maybe not needed, but very powerful)
 - Assignment/Copy semantics
 - Some of the comparison operators (!<>=, etc...)
 - Implicit casting and promotion (may harm more than help)
 - anything else?
 
 What are the good reasons not to support user defined assignment/copy
 semantics for structs?
 
 One already assumes copying of structs to be a potentially
 non-trivial operation. The default copy would need to be redefined
 from a memcpy to memberwise assignment.
A struct without reference type variables or pointers, could always be memcopied. This could go in the language spec.
 Making structs more powerful would make it possible to support both
 the limited range data types you suggest and things like transparent
 BigNum types, automatic ref-counted resource handles, automatic (and
 safe) COW types, and more...
We could implement a lot if we had structs that are sensitive to changes of their fields! (This could be implemented so, that whenever there is an assignment to the struct's field, the compiler inserts a call to user defined code!) --- I wonder, should we differentiate between - structs in general - structs with no reference or pointer variables I mean, we are already redefining in D the semantics between Objects and Structs, so why not make a proper job of it? We could call the new type Subject. The idea being that they are further away from Objects than what Structs are. - Subject contains no ptrs/refs. Memcopy. Fields can be sensitive. - Struct just like they are now - Object just like they are now To really be useful, Subjects should be usable in arithmetic and string contexts just like pre-existing data types. Probably they should contain a field that says whether they are "string friendly" or "float compatible".
Nov 03 2005
parent reply "Garett Bass" <garettbass studiotekne.com> writes:
"Georg Wrede" <georg.wrede nospam.org> wrote in message
news:436A4D5A.5050106 nospam.org...
 (This could be implemented so, that whenever there is an assignment to the
struct's field, the compiler inserts a call to user 
 defined code!
This sounds alot like the Property syntax in D. A property is a virtual method, so you can derive from a class whose values are all accessed via properties, and insert user code between the assignment and the underlying storage of the value.
Nov 03 2005
parent reply Sean Kelly <sean f4.ca> writes:
Garett Bass wrote:
 "Georg Wrede" <georg.wrede nospam.org> wrote in message
news:436A4D5A.5050106 nospam.org...
 
(This could be implemented so, that whenever there is an assignment to the
struct's field, the compiler inserts a call to user 
defined code!
This sounds alot like the Property syntax in D. A property is a virtual method, so you can derive from a class whose values are all accessed via properties, and insert user code between the assignment and the underlying storage of the value.
Like this? class C { int getSomething() { return doGetSomething(); } protected: abstract int doGetSomething(); } This is actually the suggested method for doing interfaces in C++, as it creates a clean separation between interface and implementation. Sean
Nov 03 2005
parent "Garett Bass" <garettbass studiotekne.com> writes:
In the struct-alike case, I prefer to do this:

class Base {
    private int _i;
    final int i() { return _i; }
    int i(int i) { return _i = i; }
}

class PreDerived {
    int i(int i) {
        writefln("i = %d", super.i); // old value
        return super.i = i;
    }
}

class PostDerived {
    int i(int i) {
        super.i = i;
        writefln("i = %d", super.i); // new value
        return super.i;
    }
}

This way you have the flexibility to process the input
before and/or after it is assigned to the base class's
storage.

With the protected handler method, you can only process
the input at one point in the assignment sequence, i.e.
whenever the handler is called.  Of course, in some
implementations, this may be desirable, so it's nice to
have both tools in your box ;)

BTW, I've come to realize that the opCast() operator
allows me to do just exactly what I should do to create
a pseudonumeric ufloat class.  All the debate here
worked out nicely.

Regards,
Garett


"Sean Kelly" <sean f4.ca> wrote in message
news:dkduf7$g95$1 digitaldaemon.com...
 Garett Bass wrote:
 "Georg Wrede" <georg.wrede nospam.org> wrote in message
news:436A4D5A.5050106 nospam.org...

(This could be implemented so, that whenever there is an assignment to the
struct's field, the compiler inserts a call to user 
defined code!
This sounds alot like the Property syntax in D. A property is a virtual method, so you can derive from a class whose values are all accessed via properties, and insert user code between the assignment and the underlying storage of the value.
Like this? class C { int getSomething() { return doGetSomething(); } protected: abstract int doGetSomething(); } This is actually the suggested method for doing interfaces in C++, as it creates a clean separation between interface and implementation. Sean
Nov 03 2005
prev sibling parent "Lionello Lunesu" <lio remove.lunesu.com> writes:
 From the CPU's point of view, the difference is evident when multiplying.
There are more operations that are different for unsigned and signed integers: shifting (sign extension) and comparisons (less than <-> smaller than). I use "uint" everywhere in my array classes. Not for the larger range (although one could claim this is necessary for an array class: it should be able to span all memory and therefor needs all bits), but for easier range checking: T& operator [] ( uint i ) { assert(i<length); return ptr[i]; } whereas with an signed int you'd need two comparisons: T& operator [] ( int i ) { assert(i>=0 && i<length); return ptr[i]; } This is just one example where I definately don't want just a restricted integer: I don't need the full range, but since negative values make no sense, and the generated 'unsigned' code is shorter, I use an unsigned integer. Because the FPU has no similar concept, like unsigned float, I do think it should not be a built-in type, but some class with overriden operators. L.
Nov 03 2005