digitalmars.D - Possible unsigned float type?
- Garett Bass (16/16) Oct 31 2005 I would really like to have an unsigned float type for a project I'm wor...
- Regan Heath (8/27) Nov 01 2005 A while back Arcane Jill wrote a big integer class which had similar
- =?ISO-8859-1?Q?Jari-Matti_M=E4kel=E4?= (7/11) Nov 01 2005 IMHO even if you could use unsigned types, you should always explicitly
- Don Clugston (34/55) Nov 02 2005 I'd like to challenge the underlying concept here.
- kris (2/67) Nov 02 2005
- Garett Bass (6/6) Nov 02 2005 I beg to differ, I do not want a "positive float". I want to represent ...
- Garett Bass (3/10) Nov 02 2005 To clarify, I'm suggesting an IEEE floating point value where the sign b...
- =?ISO-8859-1?Q?Jari-Matti_M=E4kel=E4?= (14/31) Nov 02 2005 In mathematics, the signum has three different values [1]. Surely you do...
- Garett Bass (3/5) Nov 03 2005 I don't mind doing this. Part of my original post was a question as to ...
- Don Clugston (25/35) Nov 03 2005 OK, perhaps there is less ambiguous word than 'positive'.
- Oskar Linde (19/27) Nov 03 2005 This would be most useful. Although, I think a higher goal should be to ...
- Georg Wrede (25/63) Nov 03 2005 IIRC, this is how it is done in Euphoria. Then we'd have OddInteger (as
- Garett Bass (3/5) Nov 03 2005 This sounds alot like the Property syntax in D. A property is a virtual...
- Sean Kelly (12/19) Nov 03 2005 Like this?
- Garett Bass (34/53) Nov 03 2005 In the struct-alike case, I prefer to do this:
- Lionello Lunesu (17/18) Nov 03 2005 There are more operations that are different for unsigned and signed
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
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
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
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
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
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
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
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...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_functionI 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
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
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
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
Oskar Linde wrote:Don Clugston says...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.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.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
"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
Garett Bass wrote:"Georg Wrede" <georg.wrede nospam.org> wrote in message news:436A4D5A.5050106 nospam.org...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(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
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...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(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
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