3

My take on this would be

#include <iostream>

int main()
{
    for( int i = 0; i < 20; ++i) {
        std::cout << (char) ((random() % (int('Z') + 1)) + int('A'))  << '\n';
    }
}

This seems to be very straight forward. You generate a number, that is between everything lower or equal to Z and greater or equal to A. If you play with it, you will find that there are also other chars generated. Why is that?

User12547645
  • 6,955
  • 3
  • 38
  • 69

6 Answers6

8

With <random>, and not assuming ASCII, you might do:

const std::string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
constexpr std::size_t output_size = 20;
std::mt19937 rng{std::random_device{}()};
std::uniform_int_distribution<> dis(0, alphabet.size() - 1);
std::string res;
res.reserve(output_size);

std::generate_n(std::back_inserter(res),
                output_size,
                [&](){ return alphabet[dis()]; });
Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • 1
    There's nothing documented about this, but doesn't the inherit method of how these algorithms work mean your output would always be "ordered" (If A shows up in the sample it will always be first)? – NathanOliver Jan 14 '20 at 13:41
  • @NathanOliver: Oops, indeed, `std::sample` is not the right tool here. – Jarod42 Jan 14 '20 at 13:56
  • @NathanOliver Are you referring to the *stable* remark [here](http://eel.is/c++draft/alg.random.sample)? It appears to be so. – Bob__ Jan 14 '20 at 13:56
  • @Jarod42 Not neccessarly, you just have to shuffle the outputted result. – Bob__ Jan 14 '20 at 13:57
  • @Bob__ I'm just referring to everything I've ever seen on a single pass sampler like `std::sample`. I've never seen one where the output wasn't ordered the same way the input was. – NathanOliver Jan 14 '20 at 13:58
  • @Jarod42 I like the change, but mabye make that an addition to your answer or just a new answer instead? All the votes and the accepts are on your old answer, not this new one. – NathanOliver Jan 14 '20 at 13:59
  • @Bob__: `"AAAAAAAA"` won't be generated with `std::sample`, but it OP attempt's allow that. – Jarod42 Jan 14 '20 at 14:00
  • @NathanOliver: but my answer with `std::sample` was wrong (even if up-voted)... – Jarod42 Jan 14 '20 at 14:02
5
char c = *("ABCDEFGHIJKLMNOPQRSTUVWXYZ" + rand() % 26);

is at least portable. Note the use of pointer arithmetic on the const char[27] constant which decays to a const char* type in the expression. Switch out rand() for something out of std::random if the above is not sufficiently random.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
3

Your math is wrong. Assuming ASCII, (random() % (int('Z') + 1) could return anything up to 'Z', including lowercase characters, numbers, unprintable characters and other things. If you add int('A') to that, you got a high change of getting a result that's outside of the uppercase characters, and even over 127 and therefore not ASCII anymore.

You could simply have 'A' + (random() % 26) instead.

Blaze
  • 16,736
  • 2
  • 25
  • 44
1

Another option is to use std::shuffle. You can use that to mix up your alphabet and take the first N characters you need from that shuffled string. That would look like

std::string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
std::shuffle(alphabet.begin(), alphabet.end(), std::mt19937{std::random_device{}()});
std::cout << alphabet.substr(20); // N in this case
NathanOliver
  • 171,901
  • 28
  • 288
  • 402
  • I like this one too, noting of course that it's impossible in this scheme to draw the same digit twice, you're late to the party. Have an upvote! – Bathsheba Jan 14 '20 at 13:46
  • @Bathsheba Better late then never ;) Thanks. Yeah, wasn't sure if uniqueness was required or not. – NathanOliver Jan 14 '20 at 13:47
0

'Z' equals to 90, so the code:

(random() % (int('Z') + 1)

Generates numbers between 1 and 90. Then you add 'A' which is 65, so your numbers are in range 66 - 155. To fix it you have to change your code to:

std::cout << (char) ((random() % (int('Z' - 'A') + 1)) + int('A'))  << '\n';
Hawky
  • 441
  • 1
  • 3
  • 10
-1

Well, I would write it this way. It just samples a RNG in the range of 'A' to 'Z', and then casts it to char.

std::mt19937 rng{ std::random_device{}() };
std::uniform_int_distribution<> dis('A', 'Z');
std::cout << static_cast<char>(dis(rng));
kookie
  • 49
  • 3