"K. Frank" <kfrank29.c@gmail.com>: Jun 17 02:19PM -0700 Hello Paul! On Tuesday, June 16, 2015 at 3:12:30 PM UTC-4, Paul wrote: > I tried the problem of generating solutions like 123 - 45 - 67 + 89 = 100. The point is that we get 100 and we use the digits from 1 to 9 in consecutive order. > My code is really ugly, and it also took me ages to do. Any insights on how I can improve it? The problem is stated more accurately in the initial comments. > Many thanks for your help. I have some thoughts, but take them with a grain of salt. There are generally lots of different ways of doing things. There are also style preferences for how much generality, abstraction, and hewing to prescriptive "good practices" one wants to deal with. > Write a program that outputs all possibilities to put + or - or nothing between the numbers 1, 2, ..., 9 (in this order) > such that the result is always 100. For example: 1 + 2 + 34 - 5 + 67 - 8 + 9 = 100.*/ > // First a utility function that inserts + and - into a vector of numbers to get a result There is a question of what level of granularity one wants for helper functions for a problem like this. You only call insertSigns once in your code. If it were me, I might not package a code fragment like this in a separate function. (But that's just me.) > int insertSigns (const std::vector<int>& numbers, const std::string& plusesAndMinuses) > ... I think you can simplify things (get rid of things like concatenate and insertSigns and so on) if you organize your problem as follows: Recognize that there are three ways of linking neighboring digits together: a plus sign, a minus sign, or concatenate the digits together to form a multi-digit number. Thus, maybe enum Operation { concat, plus, minus }; > ... > // Generate all combinations of plus/minus signs of a given length. Use recursion First, you have stated a specific problem (single digits, 1 through 9, in order), and you haven't stated a generalized version of the problem. I would therefore write specific code -- I would bake the specifics of the problem into my data and algorithm -- rather than write more general helper functions. If you write a more general function, you (or at least I) can't say whether it's right or wrong, because you haven't set forth the more general specification that your function should satisfy. So I might use the following data structure: const int nOperations = 8; // there are eight concat's, '+'s, or '-'s inserted // between 9 digits. Operation operations[nOperations]; I would lean against recursion, and just use a simple loop. There are 3^8 = 6561 choices for how you insert concat, '+', or '-' between the 9 digits. (That is, the data structure operations can take on 3^8 distinct values.) > // Generate all vectors of numbers that can arise from concatenations in a list of numbers > // Numbers can only be concatenated with their neighbours. Use recursion > std::vector<std::vector<int>> concatenation (const std::vector<int>& numbers, int base = 10) (Again, without a more general problem having been stated, I would elect not to support the generality of having a base other than 10.) Again, I would use a loop rather than recursion. Also, if you use an array (or vector, etc) of Operations as your primary data structure, the loop where you generate the pluses and minuses and the (implicit) loop where you (implicitly) generate your concatenations can be one and the same. > ... Anyway, just some thoughts. Good luck. K. Frank |
Luca Risolia <luca.risolia@linux-projects.org>: Jun 17 05:32PM +0200 On 17/06/2015 15:18, K. Frank wrote: > If one were to redesign c++ without backward compatibility > as a goal, would it make sense to include both class enum > and old-fashioned (pre-c++11) enum? Why not (see below). > Are there use cases where plain enum is better (enough > better to be worth the weight of having two different kinds > of enum in the language)? old-style enum's can make the code more readable in some cases. For example, I find them useful for getting elements from tuples or pairs: enum {Description, RGB}; std::map<std::string, std::uint32_t> colors = { {"white", 0xffffff}, {"black", 0x000000} /*...*/ }; // somewhere else... for (const auto& c : colors) std::cout << std::get<Description>(c) << ' ' << std::hex << std::get<RGB>(c) << '\n'; The same readability cannot be achieved with strongly typed enums (or type aliases). There are other cases in template metaprogramming where they are useful. |
"K. Frank" <kfrank29.c@gmail.com>: Jun 17 12:24PM -0700 Hi Luca! On Wednesday, June 17, 2015 at 11:33:01 AM UTC-4, Luca Risolia wrote: > << std::hex << std::get<RGB>(c) << '\n'; > The same readability cannot be achieved with strongly typed enums (or > type aliases). Nice example. > There are other cases in template metaprogramming where they are useful. Are all of the use cases you have in mind based on the fact that you can templatize on integral values, but not other kinds of values, and therefore there is a role for (old-fashioned) enums that are integral types? If you were redesigning c++ (without regard to backward compatibility), given that each additional language feature adds complexity, would you keep both kinds of enums (with this template usage in mind); keep only class enums, and work out some other way to templatize on class enums; or keep only class enums and forgo the ability to templatize on enums? Thanks. K. Frank |
Thomas 'PointedEars' Lahn <PointedEars@web.de>: Jun 17 03:03PM Victor Bazarov wrote: >> I used the hammer »placement new«. > Yes, you did. Your program still has undefined behavior. See my other > reply to your use of placement new. Where is it? |
Victor Bazarov <v.bazarov@comcast.invalid>: Jun 17 12:05PM -0400 On 6/17/2015 11:03 AM, Thomas 'PointedEars' Lahn wrote: >> Yes, you did. Your program still has undefined behavior. See my other >> reply to your use of placement new. > Where is it? I'm not sure how to lead you to it precisely... It's in this thread, in answer to Stefan's "Now, why /does/ the following work?" which he posted (as reported by my Thunderbird) on 6/15/2015 at 10:18 PM; my reply dated 10:42 PM same day. > [..] V -- I do not respond to top-posted replies, please don't ask |
Bo Persson <bop@gmb.dk>: Jun 17 05:19PM +0200 On 2015-06-16 19:47, Richard wrote: >> intptr_t and/or uintptr_t from cstdint. Although they don't >> have to exist. > It's kinda annoying that these are optional. Yes, but it allows C and C++ to be implemented on systems where void* is larger than all integer types. For example word-addresses machines where char* and void* can be larger than int*. Bo Persson |
Bo Persson <bop@gmb.dk>: Jun 17 05:24PM +0200 On 2015-06-16 20:16, Melzzzzz wrote: > Too ,bad ;( > I need intptr_t as conversion is actually passing int parameter as void* > and than back to int. If you limit yourself to systems where the types exist, that might be all you need. Systems where these types are missing are extremely rare, and you might not want to run your programs there anyway, because of other peculiarities of these systems (like 48-bit ints, etc). Bo Persson |
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