C++ Playfair with 16x16 matrix decryption issue - c++

I'm writing a simple program in which I take a .txt file read it and encrypt or decrypt it with the Playfair algorithm using a 16x16 ASCII cipher.
When I decypher a file I get it mostly correct the only issue is that the char 'o' is replaced with '_' and random sections of the text are not deciphered right.
Example:
"as she swam l z}"d~o*dd/y``6� {;/~v_(tb_)uesp4�prxnc(z�icehr,P`(yc'eezm"-ickin_)"
This is the section of the code that I use to decipher it. At this point I already generated the matrix and read the input file. In the encryption code if a and b are equal b is set to NULL, the last if statement checks that. The variable besedilo is the whole text of the file and M is the 16x16 matrix.
for(int t = 0; t < besedilo.size()-2;t+=2){
char a = besedilo[t];
char b = besedilo[t+1];
int it, jt, k = 0,f = 0, i=0,j=0;
for(it = 0; it < 16; it++){
for(jt = 0; jt < 16; jt++){
if(a == M[it][jt]){
i = it;
j = jt;
}
if(b == M[it][jt]){
k = it;
f = jt;
}
}
}
if((i != k)&&(j != f)){
a = M[i][f];
b = M[k][j];
}else if(i == k){
a = M[i][(j-1)%16];
b = M[k][(f-1)%16];
}else if(j == f){
a = M[(i-1)%16][j];
b = M[(k-1)%16][f];
}
if(b == NULL){
b = a;
}

Your issue is that % does not wrap with negative numbers. Instead you are indexing negatively when any of your positions are in the 0th column or index as then you are doing (0 - 1) % 16 which is -1. See this response here: Modulo operator with negative values for the issue.
You can easily solve this with a small helper function that handles the wrapping for you, see How to make the mod of a negative number to be positive? for a possible solution.

Related

How to get all possibilities of adding two indexes inside an infinite array in c++

Ok so I am learning c++ and I got stumped with this in the language. Ok so say I have an infinite list ,and I want to figure out all the possible additions with it. EX [1,2,3] = 1 +2, 1+3, 2+1, 2+3, 3+1, 3+2.... and it would be with a list that would be so huge that I wouldn't be able to put every specific index into there.
Here were I ideas I was thinking ,but didn't work
bool sum(){
int b[] = {1, 5, 3, 9};
int n;
int equation;
for(n = 0; n < 4; ++n){
equation = Array[n] + Array [n+1 || n +2 || n+3 || n+4];
if(equation == 10){
return true;
}
}
return false;
}
I swear if feels like I am missing an equation or it's something right under my nose.
In this situation, you want to use a nested for loop.
The logic goes as follows: for every element in b, also check every element in b, and see if the sum adds up to 10.
for (size_t i = 0; i < sizeof(b); ++i){ //.length returns syntax error with //arrays
for (size_t j = 0; j < sizeof(b); ++j){// same as previously stated
if (i == j) continue; //So that you don't add the number to itself
if (b[i] + b[j] == 10){
return true;
}
}
}
return false
Output:
1
we know one is true so we know this solves the problem

Segmentaion fault possible because of map

I wrote a code which has to take two string as input. It has to output number of steps(adjacent letter flips or flipping first and last letter) it takes one word to convert to another. It gives correct values till the size of string is 8. If the size of string is more than 8, it gives segmentation fault. I could not find any mistake. Can anyone please help me out. Thanks in advance. This is the code:
map<string,int>imap;
int easyStrings(string a, string b) {
//cout<<a<<endl;
if(a.compare(b) == 0)
return 0;
map<string,int>::iterator it = imap.find(a);
if(it != imap.end())
return it->second;
imap.insert(pair<string,int>(a,-2));
int min = -2;
string str = a;
str[0] = a[a.length()-1];
str[a.length()-1] = a[0];
it = imap.find(str);
if(it == imap.end() || it->second != -2)
min = 1 + easyStrings(str,b);
for(int i = 0 ; i < a.length()-1; i++)
{
string check = a;
check[i] = a[i+1];
check[i+1] = a[i];
int steps = 0;
it = imap.find(check);
if(it == imap.end() || it->second != -2)
{
steps = 1 + easyStrings(check,b);
if(steps < min || min ==-2)
if(steps > 0)
min = steps;
}
}
imap[a] = min;
return min;
}
I tried using debugger. I shows error in imap.insert(pair(a,-2));. It also gives a huge trace showing problems mainly with malloc.
It does not go into infinite recursion. There are factorial of length of input string at maximum and I only insert a string when it is not found in map.
A cursory glance at this function with gdb reveals that this function is recursive, and that strings over a certain length trigger it to enter infinite-depth recursion (or at least a depth that 4 gigs of RAM can't handle). I would look at your recursion conditionals and double check that there is an exit case that will be met for all of them.

What Ruzzle board contains the most unique words?

For smart phones, there is this game called Ruzzle.
It's a word finding game.
Quick Explanation:
The game board is a 4x4 grid of letters.
You start from any cell and try to spell a word by dragging up, down, left, right, or diagonal.
The board doesn't wrap, and you can't reuse letters you've already selected.
On average, my friend and I find about 40 words, and at the end of the round, the game informs you of how many possible words you could have gotten. This number is usually about 250 - 350.
We are wondering what board would yield the highest number of possible words.
How would I go about finding the optimal board?
I've written a program in C that takes 16 characters and outputs all the appropriate words.
Testing over 80,000 words, it takes about a second to process.
The Problem:
The number of game board permutations is 26^16.
That's 43608742899428874059776 (43 sextillion).
I need some kind of heuristic.
Should I skip all boards that have either z, q, x, etc because they are expected to not have as many words? I wouldn't want to exclude a letter without being certain.
There is also 4 duplicates of every board, because rotating the board will still give the same results.
But even with these restrictions, I don't think I have enough time in my life to find the answer.
Maybe board generation isn't the answer.
Is there a quicker way to find the answer looking at the list of words?
tldr;
S E R O
P I T S
L A N E
S E R G
or any of its reflections.
This board contains 1212 words (and as it turns out, you can exclude 'z', 'q' and 'x').
First things first, turns out you're using the wrong dictionary. After not getting exact matches with Ruzzle's word count, I looked into it, it seems Ruzzle uses a dictionary called TWL06, which has around 180,000 words. Don't ask me what it stands for, but it's freely available in txt.
I also wrote code to find all possible words given a 16 character board, as follows. It builds the dictionary into a tree structure, and then pretty much just goes around recursively while there are words to be found. It prints them in order of length. Uniqueness is maintained by the STL set structure.
#include <cstdlib>
#include <ctime>
#include <map>
#include <string>
#include <set>
#include <algorithm>
#include <fstream>
#include <iostream>
using namespace std;
struct TreeDict {
bool existing;
map<char, TreeDict> sub;
TreeDict() {
existing = false;
}
TreeDict& operator=(TreeDict &a) {
existing = a.existing;
sub = a.sub;
return *this;
}
void insert(string s) {
if(s.size() == 0) {
existing = true;
return;
}
sub[s[0]].insert(s.substr(1));
}
bool exists(string s = "") {
if(s.size() == 0)
return existing;
if(sub.find(s[0]) == sub.end())
return false;
return sub[s[0]].exists(s.substr(1));
}
TreeDict* operator[](char alpha) {
if(sub.find(alpha) == sub.end())
return NULL;
return &sub[alpha];
}
};
TreeDict DICTIONARY;
set<string> boggle_h(const string board, string word, int index, int mask, TreeDict *dict) {
if(index < 0 || index >= 16 || (mask & (1 << index)))
return set<string>();
word += board[index];
mask |= 1 << index;
dict = (*dict)[board[index]];
if(dict == NULL)
return set<string>();
set<string> rt;
if((*dict).exists())
rt.insert(word);
if((*dict).sub.empty())
return rt;
if(index % 4 != 0) {
set<string> a = boggle_h(board, word, index - 4 - 1, mask, dict);
set<string> b = boggle_h(board, word, index - 1, mask, dict);
set<string> c = boggle_h(board, word, index + 4 - 1, mask, dict);
rt.insert(a.begin(), a.end());
rt.insert(b.begin(), b.end());
rt.insert(c.begin(), c.end());
}
if(index % 4 != 3) {
set<string> a = boggle_h(board, word, index - 4 + 1, mask, dict);
set<string> b = boggle_h(board, word, index + 1, mask, dict);
set<string> c = boggle_h(board, word, index + 4 + 1, mask, dict);
rt.insert(a.begin(), a.end());
rt.insert(b.begin(), b.end());
rt.insert(c.begin(), c.end());
}
set<string> a = boggle_h(board, word, index + 4, mask, dict);
set<string> b = boggle_h(board, word, index - 4, mask, dict);
rt.insert(a.begin(), a.end());
rt.insert(b.begin(), b.end());
return rt;
}
set<string> boggle(string board) {
set<string> words;
for(int i = 0; i < 16; i++) {
set<string> a = boggle_h(board, "", i, 0, &DICTIONARY);
words.insert(a.begin(), a.end());
}
return words;
}
void buildDict(string file, TreeDict &dict = DICTIONARY) {
ifstream fstr(file.c_str());
string s;
if(fstr.is_open()) {
while(fstr.good()) {
fstr >> s;
dict.insert(s);
}
fstr.close();
}
}
struct lencmp {
bool operator()(const string &a, const string &b) {
if(a.size() != b.size())
return a.size() > b.size();
return a < b;
}
};
int main() {
srand(time(NULL));
buildDict("/Users/XXX/Desktop/TWL06.txt");
set<string> a = boggle("SEROPITSLANESERG");
set<string, lencmp> words;
words.insert(a.begin(), a.end());
set<string>::iterator it;
for(it = words.begin(); it != words.end(); it++)
cout << *it << endl;
cout << words.size() << " words." << endl;
}
Randomly generating boards and testing against them didn't turn out too effective, expectedly, I didn't really bother with running that, but I'd be surprised if they crossed 200 words. Instead I changed the board generation to generate boards with letters distributed in proportion to their frequency in TWL06, achieved by a quick cumulative frequency (the frequencies were reduced by a factor of 100), below.
string randomBoard() {
string board = "";
for(int i = 0; i < 16; i++)
board += (char)('A' + rand() % 26);
return board;
}
char distLetter() {
int x = rand() % 15833;
if(x < 1209) return 'A';
if(x < 1510) return 'B';
if(x < 2151) return 'C';
if(x < 2699) return 'D';
if(x < 4526) return 'E';
if(x < 4726) return 'F';
if(x < 5161) return 'G';
if(x < 5528) return 'H';
if(x < 6931) return 'I';
if(x < 6957) return 'J';
if(x < 7101) return 'K';
if(x < 7947) return 'L';
if(x < 8395) return 'M';
if(x < 9462) return 'N';
if(x < 10496) return 'O';
if(x < 10962) return 'P';
if(x < 10987) return 'Q';
if(x < 12111) return 'R';
if(x < 13613) return 'S';
if(x < 14653) return 'T';
if(x < 15174) return 'U';
if(x < 15328) return 'V';
if(x < 15452) return 'W';
if(x < 15499) return 'X';
if(x < 15757) return 'Y';
if(x < 15833) return 'Z';
}
string distBoard() {
string board = "";
for(int i = 0; i < 16; i++)
board += distLetter();
return board;
}
This was significantly more effective, very easily achieving 400+ word boards. I left it running (for longer than I intended), and after checking over a million boards, the highest found was around 650 words. This was still essentially random generation, and that has its limits.
Instead, I opted for a greedy maximisation strategy, wherein I'd take a board and make a small change to it, and then commit the change only if it increased the word count.
string changeLetter(string x) {
int y = rand() % 16;
x[y] = distLetter();
return x;
}
string swapLetter(string x) {
int y = rand() % 16;
int z = rand() % 16;
char w = x[y];
x[y] = x[z];
x[z] = w;
return x;
}
string change(string x) {
if(rand() % 2)
return changeLetter(x);
return swapLetter(x);
}
int main() {
srand(time(NULL));
buildDict("/Users/XXX/Desktop/TWL06.txt");
string board = "SEROPITSLANESERG";
int locmax = boggle(board).size();
for(int j = 0; j < 5000; j++) {
int changes = 1;
string board2 = board;
for(int k = 0; k < changes; k++)
board2 = change(board);
int loc = boggle(board2).size();
if(loc >= locmax && board != board2) {
j = 0;
board = board2;
locmax = loc;
}
}
}
This very rapidly got me 1000+ word boards, with generally similar letter patterns, despite randomised starting points. What leads me to believe that the board given is the best possible board is how it, or one of its various reflections, turned up repeatedly, within the first 100 odd attempts at maximising a random board.
The biggest reason for skepticism is the greediness of this algorithm, and that this somehow would lead to the algorithm missing out better boards. The small changes made are quite flexible in their outcomes – that is, they have the power to completely transform a grid from its (randomised) start position. The number of possible changes, 26*16 for the fresh letter, and 16*15 for the letter swap, are both significantly less than 5000, the number of continuous discarded changes allowed.
The fact that the program was able to repeat this board output within the first 100 odd times implies that the number of local maximums is relatively small, and the probability that there is an undiscovered maximum low.
Although the greedy seemed intuitively right – it shouldn't really be less possible to reach a given grid with the delta changes from a random board – and the two possible changes, a swap and a fresh letter do seem to encapsulate all possible improvements, I changed the program in order to allow it to make more changes before checking for the increase. This again returned the same board, repeatedly.
int main() {
srand(time(NULL));
buildDict("/Users/XXX/Desktop/TWL06.txt");
int glomax = 0;
int i = 0;
while(true) {
string board = distBoard();
int locmax = boggle(board).size();
for(int j = 0; j < 500; j++) {
string board2 = board;
for(int k = 0; k < 2; k++)
board2 = change(board);
int loc = boggle(board2).size();
if(loc >= locmax && board != board2) {
j = 0;
board = board2;
locmax = loc;
}
}
if(glomax <= locmax) {
glomax = locmax;
cout << board << " " << glomax << " words." << endl;
}
if(++i % 10 == 0)
cout << i << endl;
}
}
Having iterated over this loop around a 1000 times, with this particular board configuration showing up ~10 times, I'm pretty confident that this is for now the Ruzzle board with the most unique words, until the English language changes.
Interesting problem. I see (at least, but mainly) two approches
one is to try the hard way to stick as many wordable letters (in all directions) as possible, based on a dictionary. As you said, there are many possible combinations, and that route requires a well elaborated and complex algorithm to reach something tangible
there is another "loose" solution based on probabilities that I like more. You suggested to remove some low-appearance letters to maximize the board yield. An extension of this could be to use more of the high-appearance letters in the dictionary.
A further step could be:
based on the 80k dictionary D, you find out for each l1 letter of our L ensemble of 26 letters the probability that letter l2 precedes or follows l1. This is a L x L probabilities array, and is pretty small, so you could even extend to L x L x L, i.e. considering l1 and l2 what probability has l3 to fit. This is a bit more complex if the algorithm wants to estimate accurate probabilities, as the probas sum depends on the relative position of the 3 letters, for instance in a 'triangle' configuration (eg positions (3,3), (3,4) and (3,5)) the result is probably less yielding than when the letters are aligned [just a supposition]. Why not going up to L x L x L x L, which will require some optimizations...
then you distribute a few high-appearance letters (say 4~6) randomly on the board (having each at least 1 blank cell around in at least 5 of the 8 possible directions) and then use your L x L [xL] probas arrays to complete - meaning based on the existing letter, the next cell is filled with a letter which proba is high given the configuration [again, letters sorted by proba descending, and use randomness if two letters are in a close tie].
For instance, taking only the horizontal configuration, having the following letters in place, and we want to find the best 2 in between ER and TO
...ER??TO...
Using L x L, a loop like (l1 and l2 are our two missing letters). Find the absolutely better letters - but bestchoice and bestproba could be arrays instead and keep the - say - 10 best choices.
Note: there is no need to keep the proba in the range [0,1] in this case, we can sum up the probas (which don't give a proba - but the number matters. A mathematical proba could be something like p = ( p(l0,l1) + p(l2,l3) ) / 2, l0 and l3 are the R and T in our L x L exemple)
bestproba = 0
bestchoice = (none, none)
for letter l1 in L
for letter l2 in L
p = proba('R',l1) + proba(l2,'T')
if ( p > bestproba )
bestproba = p
bestchoice = (l1, l2)
fi
rof
rof
the algorithm can take more factors into account, and needs to take the vertical and diagonals into account as well. With L x L x L, more letters in more directions are taken into account, like ER?,R??,??T,?TO - this requires to think more through the algorithm - maybe starting with L x L can give an idea about the relevancy of this algorithm.
Note that a lot of this may be pre-calculated, and the L x L array is of course one of them.

BFS maze help c++

I am attempting to make a maze-solver using a Breadth-first search, and mark the shortest path using a character '*'
The maze is actually just a bunch of text. The maze consists of an n x n grid, consisting of "#" symbols that are walls, and periods "." representing the walkable area/paths. An 'S' denotes start, 'F' is finish. Right now, this function does not seem to be finding the solution (it thinks it has the solution even when one is impossible). I am checking the four neighbors, and if they are 'unfound' (-1) they are added to the queue to be processed.
The maze works on several mazes, but not on this one:
...###.#....
##.#...####.
...#.#.#....
#.####.####.
#F..#..#.##.
###.#....#S.
#.#.####.##.
....#.#...#.
.####.#.#.#.
........#...
What could be missing in my logic?
int mazeSolver(char *maze, int rows, int cols)
{
int start = 0;
int finish = 0;
for (int i=0;i<rows*cols;i++) {
if (maze[i] == 'S') { start=i; }
if (maze[i] == 'F') { finish=i; }
}
if (finish==0 || start==0) { return -1; }
char* bfsq;
bfsq = new char[rows*cols]; //initialize queue array
int head = 0;
int tail = 0;
bool solved = false;
char* prd;
prd = new char[rows*cols]; //initialize predecessor array
for (int i=0;i<rows*cols;i++) {
prd[i] = -1;
}
prd[start] = -2; //set the start location
bfsq[tail] = start;
tail++;
int delta[] = {-cols,-1,cols,+1}; // North, West, South, East neighbors
while(tail>head) {
int front = bfsq[head];
head++;
for (int i=0; i<4; i++) {
int neighbor = front+delta[i];
if (neighbor/cols < 0 || neighbor/cols >= rows || neighbor%cols < 0 || neighbor%cols >= cols) {
continue;
}
if (prd[neighbor] == -1 && maze[neighbor]!='#') {
prd[neighbor] = front;
bfsq[tail] = neighbor;
tail++;
if (maze[neighbor] == 'F') { solved = true; }
}
}
}
if (solved == true) {
int previous = finish;
while (previous != start) {
maze[previous] = '*';
previous = prd[previous];
}
maze[finish] = 'F';
return 1;
}
else { return 0; }
delete [] prd;
delete [] bfsq;
}
Iterating through neighbours can be significantly simplified(I know this is somewhat similar to what kobra suggests but it can be improved further). I use a moves array defining the x and y delta of the given move like so:
int moves[4][2] = {{0,1},{1,0},{0,-1},{-1,0}};
Please note that not only tis lists all the possible moves from a given cell but it also lists them in clockwise direction which is useful for some problems.
Now to traverse the array I use a std::queue<pair<int,int> > This way the current position is defined by the pair of coordinates corresponding to it. Here is how I cycle through the neighbours of a gien cell c:
pair<int,int> c;
for (int l = 0;l < 4/*size of moves*/;++l){
int ti = c.first + moves[l][0];
int tj = c.second + moves[l][1];
if (ti < 0 || ti >= n || tj < 0 || tj >= m) {
// This move goes out of the field
continue;
}
// Do something.
}
I know this code is not really related to your code, but as I am teaching this kind of problems trust me a lot of students were really thankful when I showed them this approach.
Now back to your question - you need to start from the end position and use prd array to find its parent, then find its parent's parent and so on until you reach a cell with negative parent. What you do instead considers all the visited cells and some of them are not on the shortest path from S to F.
You can break once you set solved = true this will optimize the algorithm a bit.
I personally think you always find a solution because you have no checks for falling off the field. (the if (ti < 0 || ti >= n || tj < 0 || tj >= m) bit in my code).
Hope this helps you and gives you some tips how to improve your coding.
A few comments:
You can use queue container in c++, its much more easier in use
In this task you can write something like that:
int delta[] = {-1, cols, 1 -cols};
And then you simple can iterate through all four sides, you shouldn't copy-paste the same code.
You will have problems with boundaries of your array. Because you are not checking it.
When you have founded finish you should break from cycle
And in last cycle you have an error. It will print * in all cells in which you have been (not only in the optimal way). It should look:
while (finish != start)
{
maze[finish] = '*';
finish = prd[finish];
}
maze[start] = '*';
And of course this cycle should in the last if, because you don't know at that moment have you reach end or not
PS And its better to clear memory which you have allocate in function

weighted RNG speed problem in C++

Edit: to clarify, the problem is with the second algorithm.
I have a bit of C++ code that samples cards from a 52 card deck, which works just fine:
void sample_allcards(int table[5], int holes[], int players) {
int temp[5 + 2 * players];
bool try_again;
int c, n, i;
for (i = 0; i < 5 + 2 * players; i++) {
try_again = true;
while (try_again == true) {
try_again = false;
c = fast_rand52();
// reject collisions
for (n = 0; n < i + 1; n++) {
try_again = (temp[n] == c) || try_again;
}
temp[i] = c;
}
}
copy_cards(table, temp, 5);
copy_cards(holes, temp + 5, 2 * players);
}
I am implementing code to sample the hole cards according to a known distribution (stored as a 2d table). My code for this looks like:
void sample_allcards_weighted(double weights[][HOLE_CARDS], int table[5], int holes[], int players) {
// weights are distribution over hole cards
int temp[5 + 2 * players];
int n, i;
// table cards
for (i = 0; i < 5; i++) {
bool try_again = true;
while (try_again == true) {
try_again = false;
int c = fast_rand52();
// reject collisions
for (n = 0; n < i + 1; n++) {
try_again = (temp[n] == c) || try_again;
}
temp[i] = c;
}
}
for (int player = 0; player < players; player++) {
// hole cards according to distribution
i = 5 + 2 * player;
bool try_again = true;
while (try_again == true) {
try_again = false;
// weighted-sample c1 and c2 at once
// h is a number < 1325
int h = weighted_randi(&weights[player][0], HOLE_CARDS);
// i2h uses h and sets temp[i] to the 2 cards implied by h
i2h(&temp[i], h);
// reject collisions
for (n = 0; n < i; n++) {
try_again = (temp[n] == temp[i]) || (temp[n] == temp[i+1]) || try_again;
}
}
}
copy_cards(table, temp, 5);
copy_cards(holes, temp + 5, 2 * players);
}
My problem? The weighted sampling algorithm is a factor of 10 slower. Speed is very important for my application.
Is there a way to improve the speed of my algorithm to something more reasonable? Am I doing something wrong in my implementation?
Thanks.
edit: I was asked about this function, which I should have posted, since it is key
inline int weighted_randi(double *w, int num_choices) {
double r = fast_randd();
double threshold = 0;
int n;
for (n = 0; n < num_choices; n++) {
threshold += *w;
if (r <= threshold) return n;
w++;
}
// shouldn't get this far
cerr << n << "\t" << threshold << "\t" << r << endl;
assert(n < num_choices);
return -1;
}
...and i2h() is basically just an array lookup.
Your reject collisions are turning an O(n) algorithm into (I think) an O(n^2) operation.
There are two ways to select cards from a deck: shuffle and pop, or pick sets until the elements of the set are unique; you are doing the latter which requires a considerable amount of backtracking.
I didn't look at the details of the code, just a quick scan.
you could gain some speed by replacing the all the loops that check if a card is taken with a bit mask, eg for a pool of 52 cards, we prevent collisions like so:
DWORD dwMask[2] = {0}; //64 bits
//...
int nCard;
while(true)
{
nCard = rand_52();
if(!(dwMask[nCard >> 5] & 1 << (nCard & 31)))
{
dwMask[nCard >> 5] |= 1 << (nCard & 31);
break;
}
}
//...
My guess would be the memcpy(1326*sizeof(double)) within the retry-loop. It doesn't seem to change, so should it be copied each time?
Rather than tell you what the problem is, let me suggest how you can find it. Either 1) single-step it in the IDE, or 2) randomly halt it to see what it's doing.
That said, sampling by rejection, as you are doing, can take an unreasonably long time if you are rejecting most samples.
Your inner "try_again" for loop should stop as soon as it sets try_again to true - there's no point in doing more work after you know you need to try again.
for (n = 0; n < i && !try_again; n++) {
try_again = (temp[n] == temp[i]) || (temp[n] == temp[i+1]);
}
Answering the second question about picking from a weighted set also has an algorithmic replacement that should be less time complex. This is based on the principle of that which is pre-computed does not need to be re-computed.
In an ordinary selection, you have an integral number of bins which makes picking a bin an O(1) operation. Your weighted_randi function has bins of real length, thus selection in your current version operates in O(n) time. Since you don't say (but do imply) that the vector of weights w is constant, I'll assume that it is.
You aren't interested in the width of the bins, per se, you are interested in the locations of their edges that you re-compute on every call to weighted_randi using the variable threshold. If the constancy of w is true, pre-computing a list of edges (that is, the value of threshold for all *w) is your O(n) step which need only be done once. If you put the results in a (naturally) ordered list, a binary search on all future calls yields an O(log n) time complexity with an increase in space needed of only sizeof w / sizeof w[0].