- About Flibble - 2 Updates
- Compute Unique Numbers in a Set - 14 Updates
- Style question using enums - 8 Updates
- cmsg cancel <tq3kge$2ngf9$2@dont-email.me> - 1 Update
Muttley@dastardlyhq.com: Jan 17 09:34AM On Mon, 16 Jan 2023 11:51:56 -0800 >MSVC's debugger was always pretty damn good. I have used it to debug >nightmare multi-threaded code created by somebody else, where I had to >pause threads at a specific line, in order to reproduce a certain bug Thats fine if you know where the line is but usually with threading issues (and to be fair non threaded code too) a bug/crash occurs due to an earlier bug or design error which in itself goes unnoticed. |
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com>: Jan 17 12:36PM -0800 > Thats fine if you know where the line is but usually with threading issues > (and to be fair non threaded code too) a bug/crash occurs due to an earlier > bug or design error which in itself goes unnoticed. Touche. Well, if there is a bug in my OpenGL code, I have not found it yet. Humm... So far, everything works and renders perfectly. My debugging issue with MSVC had to do with push_back's on a vector, then the debugger showed that it had no items. I said, shit... So, I iterated the vector and sure enough, it was not empty and all of my vector data (vertex, color, texture vertex, normals, ect...) was all there and filled in with the correct data. Strange. I was thinking if the debugger says the vector is empty, then how did all of the data get successfully uploaded to the GPU! Argh! Fwiw, here is an crude example scene of my current project: https://youtu.be/n13GHyYEfLA |
Ralf Goertz <me@myprovider.invalid>: Jan 17 09:19AM +0100 Am Mon, 16 Jan 2023 21:06:41 +0100 > > simply won't believe Bonita has more hubris and self delusion than > > an angry mouse. > And you don't check that Ralf's code does sth. completely different. I assume you don't mean to say, that I implemented your algorithm incorrectly (if I'm wrong about that will you please care to elaborate?) but that my algorithm is completely different from yours. Then, yes that was my point. I don't understand why you use such a complicated algorithm (compared to the very few lines I needed) if it doesn't outperform a much simpler approach. Of course one could say that I hid the complexity behind the call to std::shuffle() but you do the same with std::unordered_set.emplace() an co. |
Muttley@dastardlyhq.com: Jan 17 09:30AM On Tue, 17 Jan 2023 09:19:44 +0100 >but that my algorithm is completely different from yours. Then, yes that >was my point. I don't understand why you use such a complicated >algorithm (compared to the very few lines I needed) if it doesn't You must be new here :) Complexity is Bonitas calling card. |
Bonita Montero <Bonita.Montero@gmail.com>: Jan 17 02:14PM +0100 >> was my point. I don't understand why you use such a complicated >> algorithm (compared to the very few lines I needed) if it doesn't > You must be new here :) Complexity is Bonitas calling card. If you want the code to be as short and as performant as possible there's no way to program different. |
Malcolm McLean <malcolm.arthur.mclean@gmail.com>: Jan 17 07:48AM -0800 On Tuesday, 17 January 2023 at 13:13:37 UTC, Bonita Montero wrote: > > You must be new here :) Complexity is Bonitas calling card. > If you want the code to be as short and as performant > as possible there's no way to program different. A shuffle followed by taking the first elements of the vector isn't a particularly efficient way of generating a sequence of unique random numbers. But it's not all that ineffieicnt either, and there's often an advantage in writing something simply ans quickly from pre-existing components, rather than writing a tailor- made, customised solution. |
Bonita Montero <Bonita.Montero@gmail.com>: Jan 17 04:49PM +0100 Am 17.01.2023 um 16:48 schrieb Malcolm McLean: > not all that ineffieicnt either, and there's often an advantage in writing something > simply ans quickly from pre-existing components, rather than writing a tailor- > made, customised solution. You don't have real randomness by shuffling. |
Muttley@dastardlyhq.com: Jan 17 04:25PM On Tue, 17 Jan 2023 07:48:02 -0800 (PST) >A shuffle followed by taking the first elements of the vector isn't a >particularly >efficient way of generating a sequence of unique random numbers. But it's Just out of interest, what would be a better way? You could randomly select elements in a container then delete that particular element so it doesn't get used again but I'm not sure that would be very efficient beyond single digit container sizes. Ditto starting at a random point in the container and walking it in a random direction until you find an unused element. |
Bonita Montero <Bonita.Montero@gmail.com>: Jan 17 05:32PM +0100 Am 17.01.2023 um 16:49 schrieb Bonita Montero: >> tailor- >> made, customised solution. > You don't have real randomness by shuffling. I found that you can randomly shuffle with random_shuffle or you provide a shuffling function-object since C++17. That would be nice but if you have a large number of values and chose only a small portion from that this would take a lot of memory. |
Ralf Goertz <me@myprovider.invalid>: Jan 17 05:31PM +0100 Am Tue, 17 Jan 2023 16:49:37 +0100 > > from pre-existing components, rather than writing a tailor- made, > > customised solution. > You don't have real randomness by shuffling. What makes you say that? Have a look at the first answer to that question: <https://cs.stackexchange.com/questions/47338/whats-a-uniform-shuffle>. It shows that a properly implemented shuffle makes every permutation equally probable. What more do you need for "real randomness"? While I haven't checked the implementation of my c++ library (libstdc++6-devel-gcc12-12.2.1+git537-1.2.x86_64) I have no doubt that the authors have created a suitable one. |
Malcolm McLean <malcolm.arthur.mclean@gmail.com>: Jan 17 09:08AM -0800 > used again but I'm not sure that would be very efficient beyond single digit > container sizes. Ditto starting at a random point in the container and walking > it in a random direction until you find an unused element. You have the range 0 to N-1 to choose M unique elements from. Pick a single element x using a unifrom random number. That now gives us two ranges, 0 to x-1 and x+1 to N-1. And M-1 numbers left to pick. The number we need to pick from each range is given by the hypergeometric distribution. We have x "good" balls and N - x - 2 "bad" balls in an urn, and we withdraw M-1 balls. The number of "good" balls we draw tells us how many elemets to distribute to the first half of the range. The remainder of the elements we choose from the second half of the range. Then it's just recursive, with the range splitting on a random elemnet each level. You cna write a generator for numbers with a hypergeometric distribution naively and quite simply by taking M random numbers. Or you can do it in a far more complicated way by calculating the cumulative distribution function. If you do it the naive way, the algorithm is O(M log M) (M calls to the uniform function on each level, and log M levels of recursion). If you do it the complicated way you can improve on that. |
Muttley@dastardlyhq.com: Jan 17 05:10PM On Tue, 17 Jan 2023 17:31:57 +0100 >haven't checked the implementation of my c++ library >(libstdc++6-devel-gcc12-12.2.1+git537-1.2.x86_64) I have no doubt that >the authors have created a suitable one. To be pedantic, there's no real randomness at all if its simply generated from a mathematical function because you only need to know the seed to reproduce the sequence. To be truly random you need a hardware source such as a white noise generator. Even generators based on whats going on in the OS from users, network input etc isn't truly random and can be biased. |
Muttley@dastardlyhq.com: Jan 17 05:16PM On Tue, 17 Jan 2023 09:08:12 -0800 (PST) >the algorithm is O(M log M) (M calls to the uniform function on each level, >and log M >levels of recursion). If you do it the complicated way you can improve on that. Probably looks good on a whiteboard but there's a lot of shifting stuff about going on there so I doubt it'll be any faster (or more random) than simply doing random walks of an array until you find an unused element. But then its obviously based on the same algo as quicksort and selecting the optimal sorting function is a black art when copy costs vs comparison costs are factored in. |
Bonita Montero <Bonita.Montero@gmail.com>: Jan 17 06:18PM +0100 > such as a white noise generator. Even generators based on whats going > on in the OS from users, network input etc isn't truly random and can > be biased. You can initialize mt19937_64( (random_device())() ). That's enough randomness for this task. |
Ben Bacarisse <ben.usenet@bsb.me.uk>: Jan 17 05:32PM >>particularly >>efficient way of generating a sequence of unique random numbers. But it's > Just out of interest, what would be a better way? "Better" depends on the context. This thread has been split between comp.lang.c and comp.lang.c++ and if you have not been reading both you won't have seen all the many proposed algorithms. There are lots of possible trade-offs between the number of random number call, the amount of storage needed and sizes of the numbers involved. It isn't even clear what's wanted. The OP might have wanted just a random selection (all possible subsets equally probable) they might have wanted a random permutation (where all possible sequences of all possible subsets are equally probable). -- Ben. |
Bonita Montero <Bonita.Montero@gmail.com>: Jan 17 07:24PM +0100 Am 17.01.2023 um 17:32 schrieb Bonita Montero: > a shuffling function-object since C++17. That would be nice but if you > have a large number of values and chose only a small portion from that > this would take a lot of memory. I made a compromise between memory-consumption and performance. For the following code if more than a tenth of the range is chosen for the values I use a random-shuffle like operation. If less than a tenth of the range is chosen I an unordered_set to check for col- lisions. The decision is made depening on the PARTITIAL_THRESHOLD variable. #include <iostream> #include <vector> #include <charconv> #include <random> #include <concepts> #include <unordered_set> using namespace std; int main( int argc, char **argv ) { try { if( argc < 4 ) [[unlikely]] return cout << argv[0] << " n from to" << endl, EXIT_FAILURE; auto parse = []( char const *str, char const *err ) { size_t value; if( from_chars_result fcr = from_chars( str, str + strlen( str ), value ); (bool)fcr.ec || *fcr.ptr ) [[unlikely]] throw invalid_argument( err ); return value; }; size_t n = parse( argv[1], "wrong number of values" ); if( !n ) [[unlikely]] return EXIT_SUCCESS; size_t from = parse( argv[2], "wrong from-value" ), to = parse( argv[3], "wrong to-value" ); if( from > to ) [[unlikely]] swap( from, to ); size_t range = to - from; if( n - 1 > range ) [[unlikely]] return cout << "n is too large" << endl, EXIT_FAILURE; vector<size_t> values; mt19937_64 mt; uniform_int_distribution<size_t> uidRange( 0, range ); constexpr size_t PARTITIAL_THRESHOLD = 10; if( ++range && range / n >= PARTITIAL_THRESHOLD ) { unordered_set<size_t> valuesSet; valuesSet.reserve( n ); while( valuesSet.size() < n ) for( ; ; ) if( size_t value = uidRange( mt ); !valuesSet.contains( value ) ) { valuesSet.emplace( value ); break; } values.resize( n ); auto itSetValue = valuesSet.cbegin(); for( size_t i = 0; i != n; ) values[i++] = *itSetValue++; } else { if( !range ) throw bad_alloc(); values.resize( range ); for( size_t i = from; size_t &v : values ) v = i++; for( size_t i = 0; i != n; ) swap( values[i++], values[uidRange( mt )] ); values.resize( n ); } for( size_t i = 0; i != n; ++i ) ; //cout << values[i] << endl; } catch( exception const &exc ) { return cout << exc.what() << endl, EXIT_FAILURE; } } |
Paul N <gw7rib@aol.com>: Jan 17 04:29AM -0800 I'm attempting to write a Bridge program, and it's getting quite messy. At first I simply used a number for each bid, so my code had a lot of "magic numbers" in it. I got rid of some by using an enum, as follows: enum { B_PASS = 0, B_DOUBLE = 1, B_REDOUBLE = 2, B_1C = 15, B_1D = 18, B_1H = 21, B_1S = 24, B_1NT = 27, B_2C = 30, B_2D = 33, B_2H = 36, B_2S = 39, B_2NT = 42, B_3C = 45, B_3D = 48, B_3H = 51, B_3S = 54, B_3NT = 57, B_4C = 60, B_4D = 63, B_4H = 66, B_4S = 69, B_4NT = 72 }; This lets me do code such as if (WentMP(B_1NT, B_2NT)) { // rebid after 1NT - 2NT if (pc == 14 || (pc == 13 && tens >= 2)) { mess = _TEXT("Raise"); bid = B_3NT; } else { mess = _TEXT("Not got 25 points"); } } which is relatively clear. However, now that I'm trying to deal with suit bids as well it seems silly to deal with each bid separately. I have an enum enum { clubs, diamonds, hearts, spades, notrumps }; and a function int b(int level, int suit) { return 15 * level + 3 * suit; } which allow me to use for instance either B_1NT or b(1, notrumps) as the value for a one notrumps bid. Part of me thinks I ought to update the first enum to be more like enum { B_1NT = b(1, notrumps) } but this does not work, even if I make b inline. Presumably if would work if I made b a macro, but these are generally discouraged. I'm guessing that some syntax using constexpr might work (I've never used one of them before) but would I need to include the code for b twice, once for the constants and once as a normal function? All thoughts welcome! |
Paavo Helde <eesnimi@osa.pri.ee>: Jan 17 03:15PM +0200 17.01.2023 14:29 Paul N kirjutas: > Part of me thinks I ought to update the first enum to be more like > enum { B_1NT = b(1, notrumps) } > but this does not work, even if I make b inline. Use constexpr or consteval, depending on if you want to use b() also with non-compile-time arguments or not. constexpr int b(int level, int suit) { return 15 * level + 3 * suit; } |
"Öö Tiib" <ootiib@hot.ee>: Jan 17 05:23AM -0800 On Tuesday, 17 January 2023 at 14:29:51 UTC+2, Paul N wrote: > B_2C = 30, B_2D = 33, B_2H = 36, B_2S = 39, B_2NT = 42, > B_3C = 45, B_3D = 48, B_3H = 51, B_3S = 54, B_3NT = 57, > B_4C = 60, B_4D = 63, B_4H = 66, B_4S = 69, B_4NT = 72 }; Nameless type, SCREAMING CAPS names and then using just ints anyway? > enum { clubs, diamonds, hearts, spades, notrumps }; > and a function > int b(int level, int suit) { return 15 * level + 3 * suit; } Here you clearly want to have constexpr function. > Part of me thinks I ought to update the first enum to be more like > enum { B_1NT = b(1, notrumps) } > but this does not work, even if I make b inline. You want constexpr, not inline. The constexpr implies inline. > Presumably if would work if I made b a macro, but these are generally discouraged. I'm guessing that some syntax using constexpr might work (I've never used one of them before) but would I need to include the code for b twice, once for the constants and once as a normal function? You mix up constexpr and consteval here. The consteval function must run compile time but constexpr can be ran run time as well. |
Paul N <gw7rib@aol.com>: Jan 17 05:44AM -0800 On Tuesday, January 17, 2023 at 1:15:56 PM UTC, Paavo Helde wrote: > Use constexpr or consteval, depending on if you want to use b() also > with non-compile-time arguments or not. > constexpr int b(int level, int suit) { return 15 * level + 3 * suit; } Thanks Paavo, that's just the job. I didn't realise constexpr could handle both compile-time and non-compile-time values. |
Paul N <gw7rib@aol.com>: Jan 17 05:52AM -0800 On Tuesday, January 17, 2023 at 1:23:47 PM UTC, Öö Tiib wrote: > > B_3C = 45, B_3D = 48, B_3H = 51, B_3S = 54, B_3NT = 57, > > B_4C = 60, B_4D = 63, B_4H = 66, B_4S = 69, B_4NT = 72 }; > Nameless type, SCREAMING CAPS names and then using just ints anyway? Well, it's nearly a macro, isn't it? If you have any better ideas, I'd (seriously) be glad to hear them, that's the whole point of this post. The values aren't random, they also represent contracts, with 16 representing 1 clubs doubled, 17 representing 1 clubs redoubled, etc. > > and a function > > int b(int level, int suit) { return 15 * level + 3 * suit; } > Here you clearly want to have constexpr function. Yes, Paavo said that too and gave me the syntax. I perhaps ought to keep up more with these recent (!) developments to the language. > > Presumably if would work if I made b a macro, but these are generally discouraged. I'm guessing that some syntax using constexpr might work (I've never used one of them before) but would I need to include the code for b twice, once for the constants and once as a normal function? > You mix up constexpr and consteval here. The consteval function must run > compile time but constexpr can be ran run time as well. Thanks for the explanation. I'd heard of constexpr (but didn't know much about it) whereas I'd not heard of consteval. |
David Brown <david.brown@hesbynett.no>: Jan 17 05:00PM +0100 On 17/01/2023 14:52, Paul N wrote: > Well, it's nearly a macro, isn't it? If you have any better ideas, > I'd (seriously) be glad to hear them, that's the whole point of this > post. Macro names don't need all caps. I only ever use all-caps names if I have a macro that is doing something weird, and you have to pay special attention to it. So if I have a function-like macro that behaves very much like a function, it does not need all-caps in the name. (Of course, in C++ this generally would be a real function - it's more common in C, when you need something that is type generic and you don't have templates.) Similarly, macros that are simple constants do not need all-caps names. (And again, there are usually better choices than macros.) If the macro evaluates a parameter more than once, or plays silly buggers with scopes, declares new variables, etc., in a way that is not obvious in its use, then all-caps is a good warning. But overuse of a warning negates its effectiveness. > The values aren't random, they also represent contracts, with 16 > representing 1 clubs doubled, 17 representing 1 clubs redoubled, > etc. Then don't define them this way. Do it using a constexpr function, as discussed in other posts, or by some completely different arrangement (such as a const template variable, or a class that wraps the value while storing it in a bitfield struct - there are a number of options). Whenever there are hand-calculated magic numbers, you should be sceptical. It /might/ be the simplest and clearest way to write the code, but it might not be. And it's seldom the most /fun/ way to write the code! |
Paul N <gw7rib@aol.com>: Jan 17 08:17AM -0800 On Tuesday, January 17, 2023 at 4:00:38 PM UTC, David Brown wrote: > sceptical. It /might/ be the simplest and clearest way to write the > code, but it might not be. And it's seldom the most /fun/ way to write > the code! Thanks for the comments, David. My first attempt at the code used all the magic numbers and so having an enum was at least an improvement on that. Now that I have the function, I have more options, but it's still not entirely clear to me whether changing code from the already written bid = B_3NT; to the slightly longer bid = b(3, notrumps) is really an improvement. Hence the canvassing of opinions. |
Bo Persson <bo@bo-persson.se>: Jan 17 06:43PM +0100 On 2023-01-17 at 14:52, Paul N wrote: >>> int b(int level, int suit) { return 15 * level + 3 * suit; } >> Here you clearly want to have constexpr function. > Yes, Paavo said that too and gave me the syntax. I perhaps ought to keep up more with these recent (!) developments to the language. Yes, as recent as 2011. :-) |
Ralf Goertz <me@myprovider.invalid>: Jan 17 09:21AM +0100 removed with Claws Mail |
You received this digest because you're subscribed to updates for this group. You can change your settings on the group membership page. To unsubscribe from this group and stop receiving emails from it send an email to comp.lang.c+++unsubscribe@googlegroups.com. |
No comments:
Post a Comment