December 13, 2012 Re: Is there any reason why arithmetic operation on shorts and bytes return int? | ||||
---|---|---|---|---|
| ||||
On 2012-51-13 13:12, kenji hara <k.hara.pg@gmail.com> wrote: > D does not support such implicit *construction* in return statement and > function argument. > It is a current language design, and not a bug. Walter does not seem to agree (see his post in this discussion). Previous discussions with Andrei (see bug #8570[1] and related discussion[2]) indicates he also thinks alias this (or some other language feature) should support this. I guess this is not really relevant to this discussion, so I'll make a separate thread. [1]: http://d.puremagic.com/issues/show_bug.cgi?id=8570 [2]: http://forum.dlang.org/thread/sedknwtlaefrxuflnbez@forum.dlang.org?page=8#postjul0qv:242l9d:241:40digitalmars.com -- Simen |
December 14, 2012 Re: Is there any reason why arithmetic operation on shorts and bytes return int? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Simen Kjaeraas | On 12/13/2012 6:30 AM, Simen Kjaeraas wrote: > Walter does not seem to agree (see his post in this discussion). Note that the following implementation of halffloat does work, allowing explicit cast to halffloat and implicit conversion from. (The halffloat literals don't work at the moment because of a limitation in CTFE, I'm working with Don to resolve that.) ----------------------------------------------------------- /* * References: * http://en.wikipedia.org/wiki/Half-precision_floating-point_format */ module halffloat; struct HF { /* Provide implicit conversion of HF to float */ @property float toFloat() { return shortToFloat(s); } alias toFloat this; /* Done as a template in order to prevent implicit conversion * of argument to float. */ this(T : float)(T f) { static assert(is(T == float)); s = floatToShort(f); } /* These are done as properties to avoid * circular reference problems. */ static @property HF min_normal() { HF hf = void; hf.s = 0x0400; return hf; /* fp16!0x1p-14; */ } static @property HF max() { HF hf = void; hf.s = 0x7BFF; return hf; /* fp16!0x1.FFCp+15; */ } static @property HF nan() { HF hf = void; hf.s = EXPMASK | 1; return hf; /* fp16!(float.nan); */ } static @property HF infinity() { HF hf = void; hf.s = EXPMASK; return hf; /* fp16!(float.infinity); */ } static @property HF epsilon() { HF hf = void; hf.s = 0x3C01; return hf; /* fp16!0x1p-10; */ } enum dig = 3; enum mant_dig = 11; enum max_10_exp = 5; enum max_exp = 16; enum min_10_exp = -5; enum min_exp = -14; private: ushort s = EXPMASK | 1; // .init is HF.nan } /******************** * User defined literal for Half Float. */ template fp16(float v) { enum fp16 = HF(v); } private: // Half float values enum SIGNMASK = 0x8000; enum EXPMASK = 0x7C00; enum MANTMASK = 0x03FF; enum HIDDENBIT = 0x0400; // float values enum FSIGNMASK = 0x80000000; enum FEXPMASK = 0x7F800000; enum FMANTMASK = 0x007FFFFF; enum FHIDDENBIT = 0x00800000; // Rounding mode enum ROUND { TONEAREST, UPWARD, DOWNWARD, TOZERO }; enum ROUNDMODE = ROUND.TONEAREST; union U { uint u; float f; } ushort floatToShort(float f) { /* If the target CPU has a conversion instruction, this code could be * replaced with inline asm or a compiler intrinsic, but leave this * as the CTFE path so CTFE can work on it. */ /* The code currently does not set INEXACT, UNDERFLOW, or OVERFLOW, * but is marked where those would go. */ U uf = void; uf.f = f; uint s = uf.u; ushort u = (s & FSIGNMASK) ? SIGNMASK : 0; int exp = s & FEXPMASK; if (exp == FEXPMASK) // if nan or infinity { if ((s & FMANTMASK) == 0) // if infinity { u |= EXPMASK; } else // else nan { u |= EXPMASK | 1; } return u; } uint significand = s & FMANTMASK; if (exp == 0) // if subnormal or zero { if (significand == 0) // if zero return u; /* A subnormal float is going to give us a zero result anyway, * so just set UNDERFLOW and INEXACT and return +-0. */ return u; } else // else normal { // normalize exponent and remove bias exp = (exp >> 23) - 127; significand |= FHIDDENBIT; } exp += 15; // bias the exponent bool guard = false; // guard bit bool sticky = false; // sticky bit uint shift = 13; // lop off rightmost 13 bits if (exp <= 0) // if subnormal { shift += -exp + 1; // more bits to lop off exp = 0; } if (shift > 23) { // Set UNDERFLOW, INEXACT, return +-0 return u; } // Lop off rightmost 13 bits, but save guard and sticky bits guard = (significand & (1 << (shift - 1))) != 0; sticky = (significand & ((1 << (shift - 1)) - 1)) != 0; significand >>= shift; if (guard || sticky) { // Lost some bits, so set INEXACT and round the result switch (ROUNDMODE) { case ROUND.TONEAREST: if (guard && (sticky || (significand & 1))) ++significand; break; case ROUND.UPWARD: if (!(s & FSIGNMASK)) ++significand; break; case ROUND.DOWNWARD: if (s & FSIGNMASK) ++significand; break; case ROUND.TOZERO: break; default: assert(0); } if (exp == 0) // if subnormal { if (significand & HIDDENBIT) // and not a subnormal no more ++exp; } else if (significand & (HIDDENBIT << 1)) { significand >>= 1; ++exp; } } if (exp > 30) { // Set OVERFLOW and INEXACT, return +-infinity return u | EXPMASK; } /* Add exponent and significand into result. */ u |= exp << 10; // exponent u |= (significand & ~HIDDENBIT); // significand return u; } float shortToFloat(ushort s) { /* If the target CPU has a conversion instruction, this code could be * replaced with inline asm or a compiler intrinsic, but leave this * as the CTFE path so CTFE can work on it. */ /* This one is fairly easy because there are no possible errors * and no necessary rounding. */ int exp = s & EXPMASK; if (exp == EXPMASK) // if nan or infinity { float f; if ((s & MANTMASK) == 0) // if infinity { f = float.infinity; } else // else nan { f = float.nan; } return (s & SIGNMASK) ? -f : f; } uint significand = s & MANTMASK; if (exp == 0) // if subnormal or zero { if (significand == 0) // if zero return (s & SIGNMASK) ? -0.0f : 0.0f; // Normalize by shifting until the hidden bit is 1 while (!(significand & HIDDENBIT)) { significand <<= 1; --exp; } significand &= ~HIDDENBIT; // hidden bit is, well, hidden exp -= 14; } else // else normal { // normalize exponent and remove bias exp = (exp >> 10) - 15; } /* Assemble sign, exponent, and significand into float. * Don't have to deal with overflow, inexact, or subnormal * because the range of floats is big enough. */ assert(-126 <= exp && exp <= 127); // just to be sure //printf("exp = %d, significand = x%x\n", exp, significand); uint u = (s & SIGNMASK) << 16; // sign bit u |= (exp + 127) << 23; // bias the exponent and shift into position u |= significand << (23 - 10); U uf = void; uf.u = u; return uf.f; } import std.stdio; void main() { // HF h = fp16!27.2f; // HF j = cast(HF)( fp16!3.5f + fp16!5 ); HF f = HF(0.0f); f.s = 0x3C00; writeln("1 ", cast(float)f); f.s = 0x3C01; writeln("1.0009765625 ", cast(float)f); assert(f == HF.epsilon); f.s = 0xC000; writeln("-2 ", cast(float)f); f.s = 0x7BFF; writeln("65504 ", cast(float)f); assert(f == HF.max); f.s = 0x0400; writeln("6.10352e-5 ", cast(float)f); assert(f == HF.min_normal); f.s = 0x03FF; writeln("6.09756e-5 ", cast(float)f); f.s = 1; writeln("5.96046e-8 ", cast(float)f); f.s = 0; writeln("0 ", cast(float)f); assert(f == 0.0f); f.s = 0x8000; writeln("-0 ", cast(float)f); assert(f == -0.0f); f.s = 0x7C00; writeln("infinity ", cast(float)f); assert(f == HF.infinity); f.s = 0xFC00; writeln("-infinity ", cast(float)f); assert(f == -HF.infinity); f.s = 0x3555; writeln("0.33325 ", cast(float)f); } |
December 14, 2012 Re: Is there any reason why arithmetic operation on shorts and bytes return int? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter Bright | On Thu, Dec 13, 2012 at 05:44:23PM -0800, Walter Bright wrote: > On 12/13/2012 6:30 AM, Simen Kjaeraas wrote: > >Walter does not seem to agree (see his post in this discussion). > > Note that the following implementation of halffloat does work, allowing explicit cast to halffloat and implicit conversion from. (The halffloat literals don't work at the moment because of a limitation in CTFE, I'm working with Don to resolve that.) > ----------------------------------------------------------- Nice!! [...] > /* Provide implicit conversion of HF to float > */ > > @property float toFloat() { return shortToFloat(s); } > alias toFloat this; [...] This is cool, I've never thought of using alias this on a @property function. I'll have to start using that in my code. :-) The rest of the code is tl;dr, but I think it does showcase quite well the power of user-defined types in D. Now we just have to iron out implicit conversion from literals (and I mean that in general, not just for this particular example), and it will just be great. T -- Which is worse: ignorance or apathy? Who knows? Who cares? -- Erich Schubert |
December 14, 2012 Re: Is there any reason why arithmetic operation on shorts and bytes return int? | ||||
---|---|---|---|---|
| ||||
Posted in reply to H. S. Teoh | On 12/13/2012 10:19 PM, H. S. Teoh wrote: > This is cool, I've never thought of using alias this on a @property > function. I'll have to start using that in my code. :-) That's actually why I wrote it - as a "template" for how to do similar user defined types. > The rest of the code is tl;dr, but I think it does showcase quite well > the power of user-defined types in D. Now we just have to iron out > implicit conversion from literals (and I mean that in general, not just > for this particular example), and it will just be great. Yup. Once all that works, I'd like to incorporate halffloat into Phobos. |
December 15, 2012 Re: Is there any reason why arithmetic operation on shorts and bytes return int? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter Bright | On Fri, Dec 14, 2012 at 12:39:04AM -0800, Walter Bright wrote: > On 12/13/2012 10:19 PM, H. S. Teoh wrote: > >This is cool, I've never thought of using alias this on a @property function. I'll have to start using that in my code. :-) > > That's actually why I wrote it - as a "template" for how to do similar user defined types. [...] I'm so impressed by this trick that I decided to do a writeup of it on the wiki: http://wiki.dlang.org/Implicit_conversions_in_user_types T -- If Java had true garbage collection, most programs would delete themselves upon execution. -- Robert Sewell |
December 15, 2012 Re: Is there any reason why arithmetic operation on shorts and bytes return int? | ||||
---|---|---|---|---|
| ||||
Posted in reply to H. S. Teoh | On 12/14/2012 4:02 PM, H. S. Teoh wrote:
> I'm so impressed by this trick that I decided to do a writeup of it on
> the wiki:
>
> http://wiki.dlang.org/Implicit_conversions_in_user_types
I'd prefer to call it a "technique" rather than a "trick", because this is what alias this was designed for!
|
December 15, 2012 Re: Is there any reason why arithmetic operation on shorts and bytes return int? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter Bright | On Saturday, 15 December 2012 at 02:23:18 UTC, Walter Bright wrote:
> I'd prefer to call it a "technique" rather than a "trick", because this is what alias this was designed for!
BTW is there any idea for the timetable of multiple alas this like described in Andrei's book?
|
December 15, 2012 Re: Is there any reason why arithmetic operation on shorts and bytes return int? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Adam D. Ruppe | On 12/14/2012 6:27 PM, Adam D. Ruppe wrote:
> BTW is there any idea for the timetable of multiple alas this like described in
> Andrei's book?
Not at the moment.
|
December 16, 2012 Re: Is there any reason why arithmetic operation on shorts and bytes return int? | ||||
---|---|---|---|---|
| ||||
Posted in reply to monarch_dodra | On Tuesday, 11 December 2012 at 12:53:38 UTC, monarch_dodra wrote: > integer operations are always promoted to at least int. That's standard fare since C. I think it is a performance thing: Unpack into ints, oeprate, repack into ints. If memory serves me right, promotion to int is based more on CPU efficiency and code size than anything else (and yes packing and unpacking takes some 6 extra steps). Also with libraries possibly written by different compilers may have different results if they don't all agree on a common (default) type to return. Also most x86 operations for ints can be written as 1 byte opcodes, although for modern CPUs that kind of code generation may not be as efficient as it used to be. http://www.codeproject.com/Articles/6154/Writing-Efficient-C-and-C-Code-Optimization |
Copyright © 1999-2021 by the D Language Foundation