digitalmars.D.learn - std.conv.to vs. casting
- CJS (2/2) Jul 03 2013 I'm having trouble understanding the difference between casting
- monarch_dodra (48/50) Jul 04 2013 Casting merely changes the "observed type", whereas "to" does a
- Joseph Rushton Wakeling (9/10) Jul 04 2013 What are the speed implications of to compared to cast?
- monarch_dodra (23/38) Jul 04 2013 Speed implications, it mostly only means doing an "if (a >
- Joseph Rushton Wakeling (8/10) Jul 04 2013 The cast should be safe, as it's a size_t to a double. It's just that h...
- monarch_dodra (6/23) Jul 04 2013 I'm trying to read the bug entry, but I don't get it. Maybe a
- Joseph Rushton Wakeling (12/14) Jul 04 2013 Point is, the skip() function in std.random.RandomSample can be
- Joseph Rushton Wakeling (4/6) Jul 04 2013 By the way, CJS -- sorry to have hijacked your query. But I
- CJS (2/4) Jul 04 2013 Yes. It was a very helpful answer. I'm just glad the question I
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (24/25) Jul 04 2013 I am commenting without fully understanding the context: Both size_t and...
- Joseph Rushton Wakeling (5/27) Jul 04 2013 Oh, bugger. You mean that because it needs space to store the exponent,...
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (26/53) Jul 04 2013 converting from
- H. S. Teoh (16/25) Jul 04 2013 [...]
- monarch_dodra (3/9) Jul 04 2013 It's not about losing information, it's about being out of range.
I'm having trouble understanding the difference between casting and std.conv.to. Any help?
Jul 03 2013
On Thursday, 4 July 2013 at 06:18:21 UTC, CJS wrote:I'm having trouble understanding the difference between casting and std.conv.to. Any help?Casting merely changes the "observed type", whereas "to" does a deep conversion. Observe: ---- import std.stdio; import std.conv; void main() { int[] ints = [1, 2, 3]; auto bytes1 = cast(ubyte[])(ints); auto bytes2 = to!(ubyte[])(ints); writeln(bytes1); writeln(bytes2); } ---- [1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0] [1, 2, 3] ---- To is very useful to do "true" type conversion. It can change string width. Finally, "to" is able to do string interpretation. EG: ---- import std.stdio; import std.conv; void main() { int[] ints = to!(int[])("[1, 2, 3]"); writeln(ints); } ---- [1, 2, 3] ---- To is very convenient because it is a "one stop shop": It doesn't matter what you want to do: "to" will do it. You don't need to mix/match calls to atoi/itoa/encode/decode etc. Furthermore, it is safe: if anything fails, to will throw. It will also throw if you overflow: ---- import std.conv; void main() { int a = 500; ubyte b = cast(ubyte)(a); //No problem here: Silent overflow ubyte c = to!ubyte(a); //Runtime overflow exception } ---- Hope that helps :)
Jul 04 2013
On 07/04/2013 10:14 AM, monarch_dodra wrote:Casting merely changes the "observed type", whereas "to" does a deep conversion.What are the speed implications of to compared to cast? I ask because I see various casts in Phobos, and wonder if there isn't improved safety in preferring instead to use to, so long as the optimal speed is there with appropriate compiler optimizations. I'm particularly concerned here because of a bug I observed that would have been caught if to had been used rather than cast: http://d.puremagic.com/issues/show_bug.cgi?id=10322#c4 (I'm working on a fix, it's just time constraints that have delayed delivering it:-)
Jul 04 2013
On Thursday, 4 July 2013 at 09:31:42 UTC, Joseph Rushton Wakeling wrote:On 07/04/2013 10:14 AM, monarch_dodra wrote:Speed implications, it mostly only means doing an "if (a > T.max)". It also means adding code to handle a throw. Finally, it means the function can't be marked nothrow. I'd argue that "to" should really only be used for legitimate cases where the runtime can create out of range values, and you want to catch that as an exception. Speed should not be a real issue*. I didn't go into the details, but in your bug report, it seems like it is more of an implementation error ? In that case, an ERROR would be better. *Speed wise, it is not a problem I'd say, except maybe in range primitives, espcially empty, front and opIndex, and to a certain, popFront. It depends on the relative cost of the operation of course. For example: Cycle provides RA indexing. the code is written as: "return source[(currentIndex + inputIndex) % length];" In this specific case, there is an overflow risk, even though RA access should be un-bounded. However, it is not checked, as the implications to calling to would be problematic. Placing an assert there is better, so release does not have to pay for the check.Casting merely changes the "observed type", whereas "to" does a deep conversion.What are the speed implications of to compared to cast? I ask because I see various casts in Phobos, and wonder if there isn't improved safety in preferring instead to use to, so long as the optimal speed is there with appropriate compiler optimizations. I'm particularly concerned here because of a bug I observed that would have been caught if to had been used rather than cast: http://d.puremagic.com/issues/show_bug.cgi?id=10322#c4 (I'm working on a fix, it's just time constraints that have delayed delivering it:-)
Jul 04 2013
On 07/04/2013 12:08 PM, monarch_dodra wrote:I didn't go into the details, but in your bug report, it seems like it is more of an implementation error ? In that case, an ERROR would be better.The cast should be safe, as it's a size_t to a double. It's just that having to!double() would have identified a problem, and if the speed hit would be avoided with the use of -release -noboundscheck I'd have assumed it would be worth it. But you're right, the simplest thing to do is to fix the implementation error. Related note -- what would you anticipate about the speed hit of isNan(x) versus if(booleanValue) ... ? Yes, I'll benchmark. :-P
Jul 04 2013
On Thursday, 4 July 2013 at 10:15:22 UTC, Joseph Rushton Wakeling wrote:On 07/04/2013 12:08 PM, monarch_dodra wrote:I'm trying to read the bug entry, but I don't get it. Maybe a reduced case to explain? In any case, I don't think int to double ever throws so that wouldn't help...I didn't go into the details, but in your bug report, it seems like it is more of an implementation error ? In that case, an ERROR would be better.The cast should be safe, as it's a size_t to a double. It's just that having to!double() would have identified a problem, and if the speed hit would be avoided with the use of -release -noboundscheck I'd have assumed it would be worth it. But you're right, the simplest thing to do is to fix the implementation error. Related note -- what would you anticipate about the speed hit of isNan(x) versus if(booleanValue) ... ? Yes, I'll benchmark. :-P
Jul 04 2013
On Thursday, 4 July 2013 at 10:23:22 UTC, monarch_dodra wrote:I'm trying to read the bug entry, but I don't get it. Maybe a reduced case to explain?Point is, the skip() function in std.random.RandomSample can be called with the floating-point variable _Vprime equal to nan, _if_ popFront() or index() are called before front(). If isNan(_Vprime) && !_algorithmA then skip() will generate incorrect results. I was asking about the speed of isNan compared to if(boolean) because I was considering killing the bool _first and just using isNan(_Vprime) to check if the first sample point has already been generated. I can prepare a reduced example but it's probably simpler for me to just prepare a bugfix and do some benchmarks.
Jul 04 2013
On Thursday, 4 July 2013 at 10:32:26 UTC, Joseph Rushton Wakeling wrote:I can prepare a reduced example but it's probably simpler for me to just prepare a bugfix and do some benchmarks.By the way, CJS -- sorry to have hijacked your query. But I think you had your answer already :-)
Jul 04 2013
By the way, CJS -- sorry to have hijacked your query. But I think you had your answer already :-)Yes. It was a very helpful answer. I'm just glad the question I asked was apparently relevant to other users as well.
Jul 04 2013
On 07/04/2013 03:15 AM, Joseph Rushton Wakeling wrote:The cast should be safe, as it's a size_t to a double.I am commenting without fully understanding the context: Both size_t and double are 64 bit types on a 64-bit system. double.mant_dig being 53, converting from size_t to double loses information for many values. import std.stdio; import std.conv; void main() { size_t i = 0x8000_0000_0000_0001; double d0 = i.to!double; double d1 = cast(double)i; writefln("%s", i); writefln("%f", d0); writefln("%f", d1); } Prints 9223372036854775809 9223372036854775808.000000 9223372036854775808.000000 Still, the same information loss in a comparison may make one think that it actually worked! :p assert(d0 == i); // passes! assert(d1 == i); // passes! Ali
Jul 04 2013
On 07/04/2013 06:16 PM, Ali Çehreli wrote:I am commenting without fully understanding the context: Both size_t and double are 64 bit types on a 64-bit system. double.mant_dig being 53, converting from size_t to double loses information for many values.Oh, bugger. You mean that because it needs space to store the exponent, it has a reduced number of significant figures compared to size_t?import std.stdio; import std.conv; void main() { size_t i = 0x8000_0000_0000_0001; double d0 = i.to!double; double d1 = cast(double)i; writefln("%s", i); writefln("%f", d0); writefln("%f", d1); } Prints 9223372036854775809 9223372036854775808.000000 9223372036854775808.000000Don't understand why the error arises here, as the number of significant figures is the same for all the numbers ... ?
Jul 04 2013
On 07/04/2013 09:43 AM, Joseph Rushton Wakeling wrote:On 07/04/2013 06:16 PM, Ali Çehreli wrote:and doubleI am commenting without fully understanding the context: Both size_tconverting fromare 64 bit types on a 64-bit system. double.mant_dig being 53,exponent, it hassize_t to double loses information for many values.Oh, bugger. You mean that because it needs space to store thea reduced number of significant figures compared to size_t?Exactly.significant figuresimport std.stdio; import std.conv; void main() { size_t i = 0x8000_0000_0000_0001; double d0 = i.to!double; double d1 = cast(double)i; writefln("%s", i); writefln("%f", d0); writefln("%f", d1); } Prints 9223372036854775809 9223372036854775808.000000 9223372036854775808.000000Don't understand why the error arises here, as the number ofis the same for all the numbers ... ?It is about the difference between the significant number of bits. The size_t value above uses bits 63 and 0, a range of 64 bits. double's 53-bit mantissa has no room for bit 0. In contrast, the following size_t value can be represented exactly in a double because its representation uses only 53 bits: import std.stdio; import std.conv; void main() { size_t i = 0x001f_ffff_ffff_ffff; double d = i.to!double; writefln("%s", i); writefln("%f", d); } Prints: 9007199254740991 9007199254740991.000000 However, set any one of the currently-unset upper 11 bits (64 - 53 == 11), and you get an inexact conversion. Ali
Jul 04 2013
On Thu, Jul 04, 2013 at 06:43:16PM +0200, Joseph Rushton Wakeling wrote:On 07/04/2013 06:16 PM, Ali Çehreli wrote:[...] Yes. See: http://en.wikipedia.org/wiki/Double-precision_floating-point_format Of the 64 bits, only 53 are available for storing the mantissa (well, actually 52, but the first bit is always 1 except when the exponent is zero so it's not stored -- you get it for free). Of the remaining bits, 11 are reserved for storing the exponent, and the last for storing the sign. So the maximum precision a double can have is 53 bits. If you have a value that requires more than that, the representation will be inexact. T -- Programming is not just an act of telling a computer what to do: it is also an act of telling other programmers what you wished the computer to do. Both are important, and the latter deserves care. -- Andrew MortonI am commenting without fully understanding the context: Both size_t and double are 64 bit types on a 64-bit system. double.mant_dig being 53, converting from size_t to double loses information for many values.Oh, bugger. You mean that because it needs space to store the exponent, it has a reduced number of significant figures compared to size_t?
Jul 04 2013
On Thursday, 4 July 2013 at 16:16:08 UTC, Ali Çehreli wrote:On 07/04/2013 03:15 AM, Joseph Rushton Wakeling wrote:It's not about losing information, it's about being out of range. For example, to!float(2.0^^50) will throw an exception.The cast should be safe, as it's a size_t to a double.I am commenting without fully understanding the context: Both size_t and double are 64 bit types on a 64-bit system. double.mant_dig being 53, converting from size_t to double loses information for many values.
Jul 04 2013