Calculating percent chance - c++

So my objective is to create a random password generator of length n (n >= 5 && n <= 15) that adds in only two numbers at random locations.
(e.g. 7S4js 86dJxD h6Zqs9K)
I have this working... or so I want to believe. What I want to know is will my code ALWAYS work at determining whether or not a number should be inserted.
'newPassword': Returns a string of length 'len', using 'nums' numbers.
std::string newPassword(int len, int nums)
{
std::string password = "";
// Required numbers
int req = nums;
for (int i = 0; i < len; i++)
{
bool needNum = req > 0;
bool chance = rand() % len > req;
bool useNum = needNum && chance;
if (useNum)
req--;
char c = nextChar(useNum);
password += c;
}
return password;
}
'nextChar': Returns a random character. The character will be a number if 'isNum' is true.
char nextChar(bool isNum)
{
char c;
if (!isNum)
{
// 50% chance to decide upper or lower case
if (rand() % 100 < 50)
{
c = 'a' + rand() % 26;
}
else
{
c = 'A' + rand() % 26;
}
}
else
{
// Random number 0-9
c = '0' + rand() % 10;
}
return c;
}
So specifically, will the 'chance' variable in 'newPassword' work all the time?

rand() is an obsolete and terrible way to generate random numbers. The c++11 <random> header provides much higher quality facilities for dealing with all kinds of random stuff.
Your way of choosing the letter or a digit will not always work. I would approach it in a different way: generate the needed number of letters and digits and then shuffle the string. It might not be the most efficient way, but given your requirements for password length, I'd value code clarity more.
#include <string>
#include <random>
#include <algorithm>
std::string generatePassword(int length, int nDigits)
{
std::string password;
password.resize(length);
std::mt19937 generator{std::random_device{}()};
// Generate capital/lowercase letters
std::uniform_int_distribution<char> letterGen(0, 2 * 26 - 1);
auto digitsBeginIter = std::generate_n(password.begin(), length - nDigits,
[&letterGen, &generator]() {
auto l = letterGen(generator);
return l < 26 ? 'a' + l : 'A' + (l - 26);
});
// Generate the digits
std::uniform_int_distribution<char> digitGen('0', '9');
std::generate_n(digitsBeginIter, nDigits,
[&digitGen, &generator]() { return digitGen(generator); });
// Shuffle the string
std::shuffle(password.begin(), password.end(), generator);
return password;
}

Related

Comparing digits in number

Consistently comparing digits symmetrically to its middle digit. If first number is bigger than the last , first is wining and I have to display it else I display last and that keep until I reach middle digit(this is if I have odd number of digits), if digit don't have anything to be compared with it wins automatically.
For example number is 13257 the answer is 7 5 2.
Another one 583241 the answer is 5 8 3.
For now I am only trying to catch when number of digits is odd. And got stuck.. This is my code. The problem is that this code don't display any numbers, but it compares them in the if statement(I checked while debugging).
#include <iostream>
using namespace std;
int countDigit(int n) {
int count = 0;
while (n != 0) {
count++;
n /= 10;
}
return count;
}
int main() {
int n;
cin >> n;
int middle;
int count = countDigit(n);
if (count % 2 == 0) {
cout<<"No mid digit exsist!!";
}
else {
int lastDigit = n % 10;
middle = (count + 1) / 2;
for (int i = 0; i < middle; i++) {
for (int j = lastDigit; j<middle; j--) {
if (i > j) {
cout << i <<' ';
}
else {
cout << j;
}
}
}
}
return 0;
}
An easier approach towards this, in my opinion, would be using strings. You can check the size of the string. If there are even number of characters, you can just compare the first half characters, with the last half. If there are odd numbers, then do the same just print the middle character.
Here's what I'd do for odd number of digits:
string n;
cin>>n;
int i,j;
for(i=0,j=n.size()-1;i<n.size()/2,j>=(n.size()+1)/2;i++,j--)
{
if(n[i]>n[j]) cout<<n[i]<<" ";
else cout<<n[j]<<" ";
}
cout<<n[n.size()/2]<<endl;
We analyze the requirements and then come up with a design.
If we have a number, consisting of digits, we want to compare "left" values with "right" values. So, start somehow at the left and the right index of digits in a number.
Look at this number: 123456789
Index: 012345678
Length: 9
in C and C++ indices start with 0.
So, what will we do?
Compare index 0 with index 8
Compare index 1 with index 7
Compare index 2 with index 6
Compare index 3 with index 5
Compare index 4 with index 4
So, the index from the left is running up and the index from the right is running down.
We continue as long as the left index is less than or equal the right index. All this can be done in a for or while loop.
It does not matter, wether the number of digits is odd or even.
Of course we also do need functions that return the length of a number and a digit of the number at a given position. But I see that you know already how to write these functions. So, I will not explain it further here.
I show you 3 different examples.
Ultra simple and very verbose. Very inefficient, because we do not have arrays.
Still simple, but more compressed. Very inefficient, because we do not have arrays.
C++ solution, not allowed in your case
Verbose
#include <iostream>
// Get the length of a number
unsigned int length(unsigned long long number) {
unsigned int length = 0;
while (number != 0) {
number /= 10;
++length;
}
return length;
}
// Get a digit at a given index of a number
unsigned int digitAt(unsigned int index, unsigned long long number) {
index = length(number) - index - 1;
unsigned int result = 0;
unsigned int count = 0;
while ((number != 0) && (count <= index)) {
result = number % 10;
number /= 10;
++count;
}
return result;
}
// Test
int main() {
unsigned long long number;
if (std::cin >> number) {
unsigned int indexLeft = 0;
unsigned int indexRight = length(number) - 1;
while (indexLeft <= indexRight) {
if (digitAt(indexLeft, number) > digitAt(indexRight, number)) {
std::cout << digitAt(indexLeft, number);
}
else {
std::cout << digitAt(indexRight, number);
}
++indexLeft;
--indexRight;
}
}
}
Compressed
#include <iostream>
// Get the length of a number
size_t length(unsigned long long number) {
size_t length{};
for (; number; number /= 10) ++length;
return length;
}
// Get a digit at a given index of a number
unsigned int digitAt(size_t index, unsigned long long number) {
index = length(number) - index - 1;
unsigned int result{}, count{};
for (; number and count <= index; ++count, number /= 10)
result = number % 10;
return result;
}
// Test
int main() {
if (unsigned long long number; std::cin >> number) {
// Iterate from left and right at the same time
for (size_t indexLeft{}, indexRight{ length(number) - 1 }; indexLeft <= indexRight; ++indexLeft, --indexRight)
std::cout << ((digitAt(indexLeft,number) > digitAt(indexRight, number)) ? digitAt(indexLeft, number) : digitAt(indexRight, number));
}
}
More modern C++
#include <iostream>
#include <string>
#include <algorithm>
#include <cctype>
int main() {
if (std::string numberAsString{}; std::getline(std::cin, numberAsString) and not numberAsString.empty() and
std::all_of(numberAsString.begin(), numberAsString.end(), std::isdigit)) {
for (size_t indexLeft{}, indexRight{ numberAsString.length() - 1 }; indexLeft <= indexRight; ++indexLeft, --indexRight)
std::cout << ((numberAsString[indexLeft] > numberAsString[indexRight]) ? numberAsString[indexLeft] : numberAsString[indexRight]);
}
}
You are trying to do something confusing with nested for-cycles. This is obviously wrong, because there is nothing “quadratic” (with respect to the number of digits) in the entire task. Also, your code doesn’t seem to contain anything that would determine the highest-order digit.
I would suggest that you start with something very simple: string’ify the number and then iterate over the digits in the string. This is obviously neither elegant nor particularly fast, but it will be a working solution to start with and you can improve it later.
BTW, the sooner you get out of the bad habit of using namespace std; the better. It is an antipattern, please avoid it.
Side note: There is no need to treat odd and even numbers of digits differently. Just let the algorithm compare the middle digit (if it exists) against itself and select it; no big deal. It is a tiny efficiency drawback in exchange for a big code simplicity benefit.
#include <cstdint>
#include <iostream>
#include <string>
using std::size_t;
using std::uint64_t;
uint64_t extract_digits(uint64_t source) {
const std::string digits{std::to_string(source)};
auto i = digits.begin();
auto j = digits.rbegin();
const auto iend = i + (digits.size() + 1) / 2;
uint64_t result{0};
for (; i < iend; ++i, ++j) {
result *= 10;
result += (*i > *j ? *i : *j) - '0';
}
return result;
}
int main() {
uint64_t n;
std::cin >> n;
std::cout << extract_digits(n) << std::endl;
}
If the task disallows the use of strings and arrays, you could try using pure arithmetics by constructing a “digit-inverted” version of the number and then iterating over both numbers using division and modulo. This will (still) have obvious limitations that stem from the data type size, some numbers cannot be inverted properly etc. (Use GNU MP for unlimited integers.)
#include <cstdint>
#include <iostream>
using std::size_t;
using std::uint64_t;
uint64_t extract_digits(uint64_t source) {
uint64_t inverted{0};
size_t count{0};
for (uint64_t div = source; div; div /= 10) {
inverted *= 10;
inverted += div % 10;
++count;
}
count += 1;
count /= 2;
uint64_t result{0};
if (count) for(;;) {
const uint64_t a{source % 10}, b{inverted % 10};
result *= 10;
result += a > b ? a : b;
if (!--count) break;
source /= 10;
inverted /= 10;
}
return result;
}
int main() {
uint64_t n;
std::cin >> n;
std::cout << extract_digits(n) << std::endl;
}
Last but not least, I would strongly suggest that you ask questions after you have something buildable and runnable. Having homework solved by someone else defeats the homework’s purpose.

How to give conditions to Rand()

First time on stack overflow.
I have this assignment due for class where we have a guessing game where our program has to generate a string of Uppercase letters of n length and n different defined by the user. I got most of my assignment working but when generate the string I am lost with how I could put these conditions in place for it to work.
char create_sequence(){
return rand() % 26 + 65;
}
Do you have any tips?
If you know sequence length, you don't need amount of different characters. This is because you require length <= characters.
To create sequence of n unique characters write a separate function:
vector<char> create_sequence(int n) {
vector<char> letters;
for (char ch = 'A'; ch <= 'Z'; ++ch) {
letters.push_back(ch);
}
vector<char> sequence;
for (int i = 0; i < n; ++i) {
int index = rand() % letters.size();
sequence.push_back(letters[index]);
letters.erase(letters.begin() + index, letters.begin() + index + 1);
}
return sequence;
}
Well, personally I think you are not far from the answer:
rand() % 26 + 65
Will effectively returns an uppercase ASCII letter. As long as you initialize the random seed once srand (time(NULL));, you can then call your instruction as many times as you want to get random values. So all you miss is a simple loop. Here is an example for 5 characters:
#include <iostream>
#include <string>
#include <stdlib.h> /* srand, rand */
#include <time.h> /* time */
char randomChar(){
return rand() % 26 + 65;
}
std::string randomString(int length)
{
srand (time(NULL));
std::string rc("");
for(int i=0; i<length; ++i)
{
rc += randomChar();
}
return rc;
}
int main()
{
std::cout << "Random string (x5) is " << randomString(5) << "\n";
}

Closest Palindrome Number

I came across one of the common interview question which was to find the closest palindrome number. Say if the input is 127 then output will be 131 and if it is 125 then it should give 121 as output.
I can come up with the logic but my logic fails on certain cases like 91, 911. In these inputs it give 99 , 919 but the correct output is 88 and 909.
Algorithm steps are:
Convert the number into string.
copy first half to second half in reverse order
convert to number and measure the abs. difference with original number diff1
add 1 to half string and now copy first half to second half in reverse order
convert to number and measure the abs. difference with original number diff2
if diff1 is less than diff2 return first number else return second number
This is actually an interesting problem. Obviously what you want to do to make this more than just a brute force is to use the most significant digits and put them in the least significant digit locations to form a palindrome. (I'm going to refer to the difference between the palindrome and the original as the "distance")
From that I'm going to say that we can ignore the least significant half of the numbers because it really doesn't matter (it matters when determining the distance, but that's all).
I'm going to take an abstract number: ABCDEF. Where A,B,C,D,E,F are all random digits. Again as I said D,E,F are not needed for determining the palindrome as what we want is to mirror the first half of the digits onto the second half. Obviously we don't want to do it the other way around or we'd be modifying more significant digits resulting in a greater distance from the original.
So a palindrome would be ABCCBA, however as you've already stated this doesn't always you the shortest distance. However the "solution" is still of the form XYZZYX so if we think about minimizing the "significance" of the digits we're modifying that would mean we'd want to modify C (or the middle most digit).
Lets take a step back and look at why: ABCCBA
At first it might be tempting to modify A because it's in the least significant position: the far right. However in order to modify the least significant we need to modify the most significant. So A is out.
The same can be said for B, so C ends up being our digit of choice.
Okay so now that we've worked out that we want to modify C to get our potentially closer number we need to think about bounds. ABCDEF is our original number, and if ABCCBA isn't the closest palindrome, then what could be? Based on our little detour above we can find it by modifying C. So there are two cases, ABCDEF is greater than ABCCBA or that is less than ABCCBA.
If ABCDEF is greater than ABCCBA then lets add 1 to C. We'll say T = C+1 so now we have a number ABTTBA. So we'll test to make sure that ABCDEF - ABCCBA > ABCDEF - ABTTBA
and if so we know that ABTTBA is the nearest palindrome. As any more modifications to C would just take us more and more distant.
Alternately if ABCDEF is less than ABCCBA then we'll subtract 1 from C. Let's say V = C-1. So we have ABVVBA, which just like above we'll test: ABCDEF - ABCCBA > ABCDEF - ABVVBA and you'll have the same solution.
The trick is that ABCDEF is always between ABTTBA and ABVVBA and the only other palindrome between those numbers is ABCCBA. So you only have 3 options for a solution. and if you compare ABCDEF to ABCCBA you only need to check 2.
I don't think it will be hard for you to adapt this to numbers of any size. and in the case of an odd number of digits you'd simply have ABCBA, ABVBA and ABTBA and so on...
So just like your examples: lets take 911.
Ignore the last 1 we only take the first half (round up). so 91X.
Replace X with 9. we have 919. this is out mid point.
We know our original 911 is less than 919 so subtract 1 from our middle number so we get our second (lower bound) 909.
Compare 911 - 919 and 911 - 909
return the one with the smallest difference.
So this gives us a constant time algorithm :)
As pointed out in the comments this is not constant time in the worst case (oops), but is certainly better than a brute force approach.
This appears to be what you have, but I thought I'd elaborate to hopefully shed light on the issue as it seems to be a small programming error on your part otherwise.
This is an implementation of Naveen's and Don's algorithm. It uses Happy Yellow Face's algorithm as a test oracle.
I would be happy to see people tweak it to remove redundant steps or special cases.
gcc 4.7.3: g++ -Wall -Wextra -std=c++0x nearest-palindrome.cpp
#include <algorithm>
#include <cassert>
#include <iostream>
#include <iterator>
#include <sstream>
#include <string>
#include <vector>
// I do not have std::to_string.
template <class T>
std::string to_string(const T& v) {
std::stringstream ss;
ss << v;
return ss.str(); }
// Nor do I have std::stoi. :(
int stoi(const std::string& s) {
std::stringstream ss(s);
int v;
ss >> v;
return v; }
bool isPalindrome(int n) {
const auto s = to_string(n);
return s == std::string(s.rbegin(), s.rend()); }
int specNearestPalindrome(int n) {
assert(0 <= n);
int less = n, more = n;
while (true) {
if (isPalindrome(less)) { return less; }
if (isPalindrome(more)) { return more; }
--less; ++more; } }
std::string reflect(std::string& str, int n) {
std::string s(str);
s.resize(s.size() + n);
std::reverse_copy(std::begin(str),
std::next(std::begin(str), n),
std::next(std::begin(s), str.size()));
return s; }
bool isPow10(int n) {
return n < 10 ? n == 1 : (n % 10 == 0) && isPow10(n / 10); }
int nearestPalindrome(int n) {
assert(0 <= n);
if (n != 1 && isPow10(n)) { return n - 1; } // special case
auto nstr = to_string(n);
// first half, rounding up
auto f1 = nstr.substr(0, (nstr.size() + 1) / 2);
auto p1 = stoi(reflect(f1, nstr.size() / 2));
const auto twiddle = p1 <= n ? 1 : -1;
auto f2 = to_string((stoi(f1) + twiddle));
auto p2 = stoi(reflect(f2, nstr.size() / 2));
if (p2 < p1) { std::swap(p1, p2); }
return n - p1 <= p2 - n ? p1 : p2; }
int main() {
std::vector<int> tests = { 0, 1, 6, 9, 10, 11, 12, 71, 74, 79, 99, 100, 999, 1000, 9900, 9999, 999000 };
for (const auto& t : tests) {
std::cout <<
(nearestPalindrome(t) == specNearestPalindrome(t) ? "." : "X");
}
std::cout << std::endl;
return 0; }
Here is a generic algorithm that would work1, although using brute-force:
int findNearestPalindrome(int n) {
int less = n;
int more = n;
while(true) {
if (isPalindrome(less)) return less;
if (isPalindrome(more)) return more;
--less;
++more;
}
}
WithinisPalindrome() function, all you need to do is convert the number to a string, and then compare the string with itself reversed.
1 However, this wouldn't check for tie cases, like Ted Hopp commented. You'd have to make a few changes to make it tie-recognizable.
#include <iostream>
#include <cmath>
#include <functional>
#include <limits>
#include <sstream>
// for convience
using namespace std;
using ULL = unsigned long long int;
// calculate the number of digits
auto Len = [](auto num) -> ULL {
return floor(log10(num)) + 1; };
// extract left half of number
auto Halfn = [](auto num, auto olen) {
for (unsigned i = 0; i < olen / 2; num /= 10, ++i);
return num;
};
int main() {
ULL num; cin >> num;
// some basic checking
if (num < 10) {
cerr << "Error, enter a number >= 10";
return 0;
}
if (numeric_limits<ULL>::max() < num) {
cerr << "Error, number too large\n";
return 0;
}
cout << ([](auto num) {
auto olen = Len(num);
auto lhalf = Halfn(num, olen);
function<ULL(ULL)> palin = [olen] (auto lhalf) {
auto half = to_string(lhalf);
// this is the mirror string that needs to be
// appended to left half to form the final
// palindrome
auto tmp = half.substr(0, olen / 2);
// take care of a corner case which
// happens when the number of digits in
// the left half of number decrease, while
// trying to find a lower palindrome
// e.g. num = 100000
// left half = 100 , the value passed to the
// function palin, is 99. if all digits are 9
// then we need to adjust the count of 9,
// otherwise if i simply replicate it, i'll get
// 9999 but one more 9 is required for the
// correct output.
if (olen / 2 > tmp.size() &&
all_of(tmp.begin(), tmp.end(),
[](auto c) { return '9' == c; })) {
tmp += '9';
}
// append, convert and return
half = half + string(tmp.crbegin(),
tmp.crend());
return stoull(half);
};
auto bpalin = palin(lhalf);
auto hpalin = palin(lhalf + 1);
auto lpalin = palin(lhalf - 1);
stringstream ss;
ss << "base palindrome = " << bpalin <<'\n';
ss << "higher palindrome = "<<hpalin <<'\n';
ss << "lower palindrome = " << lpalin <<'\n';
// calculating absolute difference for
// finding the nearest palindrome
auto diffb = labs(bpalin - num);
auto diffh = labs(hpalin - num);
auto diffl = labs(lpalin - num);
auto nearest = (diffb < diffh) ?
(diffb < diffl) ? bpalin : lpalin :
(diffh < diffl) ? hpalin : lpalin;
ss << "nearest palindrome = "
<< nearest << endl;
return move(ss.str());
}(num));
} // end main
class Solution {
public String nearestPalindromic(String n) {
int order = (int) Math.pow(10, n.length()/2);
Long ans = Long.valueOf(new String(n));
Long noChange = mirror(ans);
Long larger = mirror((ans/order)*order + order+1);
Long smaller = mirror((ans/order)*order - 1 );
if ( noChange > ans) {
larger = (long) Math.min(noChange, larger);
} else if ( noChange < ans) {
smaller = (long) Math.max(noChange, smaller);
}
return String.valueOf( ans - smaller <= larger - ans ? smaller :larger) ;
}
Long mirror(Long ans) {
char[] a = String.valueOf(ans).toCharArray();
int i = 0;
int j = a.length-1;
while (i < j) {
a[j--] = a[i++];
}
return Long.valueOf(new String(a));
}
}
Javascript Solution:
const findNearestPalindrome = n => {
if (!n) return 0;
let lowestPalindorm = lowestPalindromeHelper(n);
let largestPalindrome = largestPalindromeHelper(n);
let closestPalindrome = 0;
closestPalindrome =
Math.floor(n - lowestPalindorm) > Math.floor(largestPalindrome - n)
? largestPalindrome
: lowestPalindorm;
console.log(closestPalindrome);
};
//lowestPalindrome check
const lowestPalindromeHelper = num => {
for (let i = num - 1; i >= 0; i--) {
if (isPalindrome(i.toString())) {
return i;
}
}
};
//largest Palindrome Check
const largestPalindromeHelper = num => {
for (let i = num + 1; i <= Number.MAX_SAFE_INTEGER; i++) {
if (isPalindrome(i.toString())) {
return i;
}
}
};
const isPalindrome = n => {
return (
n ===
n
.split('')
.reverse()
.join('')
);
};
findNearestPalindrome(1234);

Figuring out the number corresponding to a letter of the alphabet?

I'm trying to duplicate the way excel provides labels its columns where
A = 1
B = 2
so on and so forth, so that it eventually reaches
AB
AC
AD
etc, etc.
How do I algorithmically take a number (like 52) and convert it to its equivalent alphabet representation?
string get(int a) {
a--; // Reduce by one to make the values with 1 letter 0..25,
// with two - 26.. 26^2-1 and so on
int val = 0; // number of columns with no more then given number of letters
int number = 0;
while (val < a) {
val = val*26 + 26;
number++;
}
val = (val - 26)/26;
a -= val; // subtract the number of columns with less letters
string res;
for (int i = 0; i < number; ++i) {
res.push_back(a%26 + 'A');
a /= 26;
}
reverse(res.begin(), res.end());
return res;
}
Hope that helps.
for two letters
#include <iostream>
#include <string>
using namespace std;
string int2alphas(int i) {
string res;
if (i > 26 - 1)
res.push_back(i / 26 + 'A' - 1);
else
res.push_back(' ');
res.push_back(i % 26 + 'A');
return res;
}
void test(int t) {
cout << t << "-" << int2alphas(t) << endl;;
}
int main() {
for (int i = 0; i < 55; i++)
test(i);
}
Convert.ToInt32("52", 26).... And now just create the correct base implementation.
? homework ?
You may think of writing some algo like:
ConvertToAlphaCode(number input)
{
Array Chars=[A-Z]
if (number<= 26)
return Chars[number-1]
else
...
}
Have a look:
A, B, C, D, ..., Y, Z, AA, AB, AC, AD, ..., AY, AZ, BA, BB, ...
is exactly like:
0, 1, 2, 3, 4, ..., 9, 10, 11, 12, 13, ..., 19, 20, 21, ...
but with digits A..Z instead of 0..9. So:
Algorithmic-ally I'm not sure how I can get a number, like say 52, and convert it to the equivalent alphabet representation..
You need to use a generic algorithm to convert a number in base-N to base-M (like decimal to hexadecimal), but with N equal to 10 and M equal to 26 (letters), and make sure that you use correct characters to represent the final "digits". As simple as that!
This will do it quite well:
string calcString(int number)
{
string returnValue = "";
do
{
int rm = number % 26;
returnValue += (char)(rm+ 'A');
number = (number - rm) / 26;
}
while (number > 0);
return returnValue;
}
For example, calcString(11); results in L.
If this is not precisely the calculation for which you were looking, leave a comment to clarify what you want and I'll come back to change it.
From number to letter:
static std::string const letters( "ABCDEFGHIJKLMNOPQRSTUVWXYZ" );
assert( n >= 0 && n < letters.size() );
return letters[n];
From letter to number:
static std::string const letters( "ABCDEFGHIJKLMNOPQRSTUVWXYZ" );
char const* result = std::find(
letters.begin(),
letters.end(),
isupper( static_cast< unsigned char >( l ) );
assert( result != letters.end() );
return result - letters.begin();
EDIT:
This just handles a single character in each direction. For more, it's
just a base 26 conversion, using the usual conversion routine.
This will work with all types of letters (small, big).
using namespace std;
int lettervalue (string l) {
l=l[0];
string alpha="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
int idx = alpha.find(l)+1;
if(idx>26){
idx=idx-26;
}
return idx;
}
To use it:
cout << lattervalue("e"); //will return 5(int)

How can I make my implementation of Project Euler 25 faster, so I can actually compute the answer?

Here is my implementation of Problem 25 - Project Euler (see comments in code for explanation of how it works):
#include <iostream> //Declare headers and use correct namespace
#include <math.h>
using namespace std;
//Variables for the equation F_n(newTerm) = F_n-1(prevTerm) + Fn_2(currentTerm)
unsigned long long newTerm = 0;
unsigned long long prevTerm = 1; //F_1 initially = 1
unsigned long long currentTerm = 1; //F_2 initially = 2
unsigned long long termNo = 2; //Current number for the term
void getNextTerms() { //Iterates through the Fib sequence, by changing the global variables.
newTerm = prevTerm + currentTerm; //First run: newTerm = 2
unsigned long long temp = currentTerm; //temp = 1
currentTerm = newTerm; //currentTerm = 2
prevTerm = temp; //prevTerm = 1
termNo++; //termNo = 3
}
unsigned long long getLength(unsigned long long number) //Returns the length of the number
{
unsigned long long length = 0;
while (number >= 1) {
number = number / 10;
length++;
}
return length;
}
int main (int argc, const char * argv[])
{
while (true) {
getNextTerms(); //Gets next term in the Fib sequence
if (getLength(currentTerm) < 1000) { //Checks if the next terms size is less than the desired length
}
else { //Otherwise if it is perfect print out the term.
cout << termNo;
break;
}
}
}
This works for the example, and will run quickly as long as this line:
if (getLength(currentTerm) < 1000) { //Checks if the next term's size is less than the desired length
says 20 or lower instead of 1000. But if that number is greater than 20 it takes a forever, my patience gets the better of me and I stop the program, how can I make this algorithm more efficient?
If you have any questions just ask in the comments.
There is a closed formula for the Fibonachi numbers (as well as for any linear recurrent sequence).
So F_n = C1 * a^n + C2 * b^n, where C1, C2, a and b are numbers that can be found from the initial conditions, i.e. for the Fib case from
F_n+2 = F_n+1 + F_n
F_1 = 1
F_2 = 1
I don't give their values on purpose here. It's just a hint.
nth fibonacci number is =
(g1^n-g2^n)/sqrt(5).
where g1 = (1+sqrt(5))/2 = 1.61803399
g2 = (1-sqrt(5))/2 = -0.61803399
For finding the length of nth fibonacci number, we can just calculate the log(nth fibonacci number).So, length of nth fibonacci number is,
log((g1^n-g2^n)/sqrt(5)) = log(g1^n-g2^n)-0.5*log(5).
you can just ignore g2^n, since it is very small negative number.
Hence, length of nth fibonacci is
n*log(g1)-0.5*log(5)
and we need to find the smallest value of 'n' such that this length = 1000, so we can find the value of n for which the length is just greater than 999.
So,
n*log(g1)-0.5*log(5) > 999
n*log(g1) > 999+0.5*log(5)
n > (999+0.5*log(5))/log(g1)
n > (999.3494850021680094)/(0.20898764058551)
n > 4781.859263075
Hence, the smallest required n is 4782. No use of any coding, easiest way.
Note: everywhere log is used in base 10.
This will probably speed it up a fair bit:
int getLength(unsigned long long number) //Returns the length of the number when expressed in base-10
{
return (int)log10(number) + 1;
}
...but, you can't reach 1000 digits using an unsigned long long. I suggest looking into arbitrary-precision arithmetic libraries, or languages which have arbitrary-precision arithmetic built in.
You could try computing a Fibonacci number using matrix exponentiation. Then repeated doubling to get to a number that has more than 1000 digits and use binary search in that range to find the first one.
using doubles, you can come to a solution knowing the highest exponential is 308:
get the sequence to the exp of 250, then divide your two numbers by 1e250. Restart the algorithm with those two numbers
if you do this 4 times, you'll get the right answer
C++ code maybe as follows:
#include "iostream"
#include "string.h"
#include "algorithm"
using namespace std;
string addTwoString(string a, string b)
{
if (a.length() == 0)
{
return b;
}
if (b.length() == 0)
{
return a;
}
reverse(a.begin(), a.end());
reverse(b.begin(), b.end());
string result = "";
string str_1, str_2;
if (a.length() > b.length())
{
str_1 = b;
str_2 = a;
}
else
{
str_1 = a;
str_2 = b;
}
int index = 0;
int value = 0, over_value = 0;
for (; index < str_1.length(); ++index)
{
int temp_1 = (int)(str_1[index] - '0');
int temp_2 = (int)(str_2[index] - '0');
int temp = temp_1 + temp_2 + over_value;
value = temp % 10;
over_value = temp / 10;
char c = (char)(value + '0');
result += c;
}
for (; index < str_2.length(); ++index)
{
int temp_2 = (int)(str_2[index] - '0');
int temp = temp_2 + over_value;
value = temp % 10;
over_value = temp / 10;
char c = (char)(value + '0');
result += c;
}
if (over_value > 0)
{
char c = (char)(over_value + '0');
result += c;
}
reverse(result.begin(), result.end());
return result;
}
int main()
{
string a = "1";
string b = "1";
string c = addTwoString(a, b);
int index = 3;
while (c.length() < 1000)
{
a = b;
b = c;
c = addTwoString(a, b);
++ index;
}
cout << index << endl;
}
I just used a recursive function that adds arrays vertically to complete the problem. Basically zero run time, less than 50 lines of code. Enjoy:
#include <stdio.h>
int Calc_Fib (int numA[], int numB[], int temp[], int index) {
int i = 0;
//Check 1000th digit for non-zero value.
if (numB[999] != 0) return index;
//Add arrays A and B vertically.
for (i = 0; i < 1000; ++i) {
temp[i] += (numA[i] + numB[i]);
if (temp[i] > 9) {
temp[i + 1] = temp[i] / 10;
temp[i] %= 10;
}
numA[i] = numB[i];
numB[i] = temp[i];
temp[i] = 0;
}
Calc_Fib(numA, numB, temp, ++index);
}
int main() {
int numA[1000]; //Holds previous term.
int numB[1000]; //Holds current term.
int temp[1000]; //Holds temporary number for vertical addition.
int i = 0;
int indexVal = 2;
for (i = 0; i < 1000; ++i) {
numA[i] = 0;
numB[i] = 0;
temp[i] = 0;
}
//Initialize first two terms.
numA[0] = (numB[0] = 1);
indexVal = Calc_Fib(numA, numB, temp, indexVal);
printf("Tada: %d\n", indexVal);
return 0;
}