Computing different terms for a given pair of exponentiation having the same result - c++

To understand the problem,let us consider these examples first:
                                 46 = (22)6 = 212 = (23)4 = 84 = 163 = 4096.
Thus,we can say that 46,212,84 and 163 are same.
                                 273 = 39 = 19683
so, both 273 and 39 are identical.
Now the problem is, for any given pair of ab how to compute all others possible (if any)xy where, ab = xy.I am interested in an algorithm that can be efficiently implemented in C/C++.
For example:
If the inputs are like this:
4,6 desired output :(2,12),(8,4)
8,4 desired output :(2,12),(2,6)
27,3 desired output :(3,9)
12,6 desired output :(144,3),(1728,2)
7,5 desired output : No duplicate possible

This is mostly a math problem. You can extract all the prime factors of a number, and you'll get a list of prime numbers and their exponents, i.e., 216000 = 26 * 33 * 53. Then take the GCD of the exponents: GCD(6,3,3) = 3. Divide the exponents by the GCD to get the smallest root of the number, 22 * 31 * 51 = 60. Then factor the GCD — factors of 3 are 1 and 3. There is one way to express the number as an integral power for each factor of the GCD. You can express it as (603)1 or (601)3.
EDIT: fixed math error.

If integers is the only thing you're interested in, you could just start extracting integer roots from the target number, and checking if the result is an integer.
You even have a convenient stop condition - whenever the root is below 2 you can stop. That is, the algorithm:
Given a result
N <- 2
Compute Nth root.
If it's an integer: add to answers
If it's < 2, exit loop
N += 1, back to previous step
This algorithm will always terminate.

I believe that this problem is equivalent to the Integer factorization problem.
I said this because we can convert any composite number to a unique product of prime numbers
(see Fundamental theorem of arithmetic) and then start creating combinations with the factors and the powers.
Update: for example: 46
we convert it to a power of a prime factor, so we have 212.
Now we increase the base exponentially and we have: 46, 84 ... until the exponent becomes 1.

I finally solved it myself.Using a naive integer factorization algorithm my solution look like this.It can be optimized further by using Pollard's rho algorithm
EDIT: Code updated, now it can handle composite bases.Please point if it has certain other bugs too :)

The smallest base that makes sense is 2. Also, the smallest exponent that makes sense is 2.
Given the result, you can determine the largest possible exponent.
Example: 4096 = 2^12, biggest exponent is 12.
This also works with results that aren't powers of 2: 19683 is a bit bigger than 2^14, so you won't be seeing any exponents bigger than 14.
Now you can take your number and work your way down from the top exponent toward 2 (the smallest exponent). For every trial exponent exp, take the exp-th root of the result; if that comes out as a clean integer, then you've found one solution.
You can use logarithms to calculate the log2 of a result, and to take the n-th root of a number. But you will need to watch out for rounding errors.
The advantage of this approach is that once you've set things up, you can just run down a simple loop, and once done you have all your results.

Related

Looking for the fastest way to divide by 2

I've searched half the day and found some very interesting things about using fixed point data types and bit shifting in C++ to accomplish division operations while avoiding floating point math. However, I have only been able to understand a small fraction of it and I can't seem to get anything to work.
All I'm wanting to do is to take two integers, ad them up, and divide by two to get the average. I need to be able to do this very quickly though, since I'm interpolating camera pixel data on an Arduino and I also have other operations to do.
So I'm confused about shifting in general. Say the integer I want to divide by two is 27. Half of 27 is 13.5. But no matter what fixed point datatype I try, I can only get 13 as an output. For example:
uint8_t x = 27;
Serial.println( x >> 1 );
returns 13
There's got to be some simple way to do this, right?
Fixed point does give you a way to represent 13.5. The Wikipedia article on the Q number format is informative: https://en.wikipedia.org/wiki/Q_(number_format)
Think of it this way: You keep using integers, but instead of taking them at face value, divide them all implicitly by a power of 2 to obtain their semantic value.
So, if using an unsigned byte as your base type (values between 0 and 255, inclusive), you might implicitly divide by 2**3 (8). Now to represent 27, you need an integer set to 27*8=>216. To divide by two, you shift one to the right; now your integer is 108, which when divided by the implicit denominator of 8 gives 13.5, the value you're expecting.
You have to realize that fixed-point number systems (and floating point too, though it's less immediately evident) still have limits, of course; certain operations will overflow no matter what you do, and some operations cause a loss of precision. This is a normal consequence of working with limited-size types.
Say the integer I want to divide by two is 27. Half of 27 is 13.5. But
no matter what fixed point data type I try, I can only get 13 as an
output.
From wikipedia Fixed-Point Arithmetic:
The scaling factor is usually a power of 10 (for human convenience) or
a power of 2 (for computational efficiency).
You actually mentioned fixed point data type, and I think that is the best approach. But no matter what you tried? Perhaps we have different understandings of fixed-point-arithmetic.
while avoiding floating point math.
Another worth while goal, though reducing in value. Even in embedded systems, I seldom had to deal with a processor that did not have floating point parts. Floating point hardware has gotten reasonably good.
Any way, using fixed point avoids any need for floating point. Even for display purposes.
I think I need to proceed with a few examples.
Fixed point Example 1: Dollars and pennies
The unit of American money is based on the dollar. The Dollar is a fixed point data type.
So, if you have 27 dollars, how do you split it with your sibling?
One way (of several) that you all know is to convert 27 dollars into 2700 pennies. Dividing this value by 2 is trivial. Now you and your sibling can each get 1350 pennies. (i.e. the penny is a fixed point data type, that easily converts to/from dollars, and vice-vesa)
Note that this is completely integer arithmetic. Adding 2 integers, and dividing by 2 (any modern compiler will choose the fastest implementation.. either integer divide or perhaps right-shift-by-2) and on my desktop these 2 actions take less than a microsecond to complete.
You should waste no more time on measuring the relative performance of those two options (divide vs right-shift), you simply enable -O3 when your code tests correct. Your compiler should be able to choose correctly.
The choice of units in any problem is based on a scale factor that covers the range of values (in your problem) AND the understandable and quickly implemented conversion between units. And note that uint64_t can describe a large amount of cash, even in pennies. (challenge to the student.)
In General, about fixed point:
Given
uint8_t x = 27;
and the desire to divide by 2 evenly and quickly... can any scale factor be something that serves your needs? I say yes.
example 2 - 50 cent coins and a dollar
How about we try, for example, a simple scale factor of 2, i.e. the unit is a hu, or half unit. (analogous to the 50-cent-coin)
uint8_t x = 27 * 1/hu; (hu = 1/2)
This means that 54 hu represents 27 units. (ie, it takes 54 50-cent-coins to add up to 27 dollars)
The fixed point solution is to scale your integer values to achieve the arithmetic required. If you scale to even values, all your integers will divide evenly to the hu units.
example 3 - nickles and a dollar
Another possible scale might be 20, both decimal (for readability) and binary for performance. (note that there are 20 nickels in a dollar)
uint16 x = 27 * 1/tu; (tu = 1/20)
Now 540 represents a scaled 27. i.e. 540 nickles
All examples are fully integer, provide exact answers, and there is a trivial mechanism to convert the values for presentation to the user. i.e. which ever fixed point used, convert to analogue of pennies, and thus 1350 pennies.
Display the penny count as a dollar
std::cout << (pennyCount / 100) << "." << (pennyCount % 100) << std::endl;
I think this should look something like (untested)
13.50
Now your challenge is to make it look nice on the output.
The reason you only get 13 is because you are actually cutting off the least significant bits when you bit shift. Since you are cutting them off, there is no remainder to check. If you are interested in what your remainder is, you could do something like:
uint8_t x = 27;
Serial.println((x - (x >> 1) - (x >> 1));
(x - (x >> 1)) should give 14 here.
it would be pretty simple to add .5 to a number once you determine whether the remainder is 1.
The following should work and should be fast:
float y = (x >> 1) + (0.5 * (x & 0x01))
What it does
(x >> 1) Divide by 2 using the bit shift
(0.5 * (x & 0x01)) Add 0.5 if the last bit was 1 (odd number)

How to calculate number of digits on huge number? C++

so the problem I have is that there is two integers (a, b) that is in [1, 10^16] interval and I need to do find out how many digits will number a^b have? Those numbers are too big for saving them on single variables, and if I write them on Array it would take a lot of time.
Is there a way to count the number a^b number of digits with some kind of formula or any simpler way then Arrays?
after fixing the one-off error suggested in the comments
number of digits of a^b = floor( b * log(a) ) + 1
karakfa has it right.
The base-k logarithm of a number n, rounded up to the nearest whole number, will give you the number of digits required to represent n in base k.
EDIT: as pointed out in comments, it should not be rounded up, but rounded down and then incremented by one. This accounts for round powers of 10 having an extra digit.
If your number is a^b then take the base-10 logarithm, log a^b and use the laws of logarithms to simplify as b log a. Note that this simplification happens inside the ceiling function so the simplification is valid. Computing log a should not be an issue (it will be between 0 and 16) and b is known. Just make sure to round after multiplying, not before.
Note that limited precision of floating-point numbers may introduce some errors into this method. If the true value of b x log a is different from the nearest floating-point representation of b x log a in such a way that they fall on different sides of an integer, the method fails. You can possibly detect when you are close to this condition and remediate it somehow.
You could use a library that supports arbitrarily large numbers, like GMP .
The core C++ language itself offers no types to work with such large numbers. So either you use a pre-existing library or write one yourself (I suggest the former - don't re-invent the wheel).

How to display a scientific number of any power in terms of any desired power

A double type variable holding the value in scientific form.Lets say
v=1.3657e-07
i want to display it in powers of -09 . In label it should look like
136.57
How can i do this? is there are any function in iomanip? or it needs to be done manually?
If you mean, how to multiply a number by 109 in C++, that's simply * 1e9.
If you literally mean, how to express the number in terms of powers of 9, i.e. in the base 9 system, then:
There is no direct support for general number system conversions in C++.
One simple approach is to take 9's logarithm of the number. The fractional part gives you a mantissa, and the integer part gives you an exponent. Then compute the base 9 representation of the mantissa.
The base R logarithm of a number x is ln(x)/ln(R).
To compute the first base 9 digit of a number x < 1, just multiply it by 9. Chop off that digit, store it, and repeat. Essentially the multiplication is shifting the digits sequence 1 step left.
If I understand the question correctly, you wish to display it as if the exponent were -9 instead of -7 (in which case your number would be 136.57).
To do this, simply multiply by the correct power and use the desired precision:
cout << fixed << setprecision( 2 ) << (v * 1e9)
Hope this helps.

Algorithm for dividing very large numbers

I need to write an algorithm(I cannot use any 3rd party library, because this is an assignment) to divide(integer division, floating parts are not important) very large numbers like 100 - 1000 digits. I found http://en.wikipedia.org/wiki/Fourier_division algorithm but I don't know if it's the right way to go. Do you have any suggestions?
1) check divisior < dividend, otherwise it's zero (because it will be an int division)
2) start from the left
3) get equal portion of digits from the dividend
4) if it's divisor portion is still bigger, increment digits of dividend portion by 1
5) multiply divisor by 1-9 through the loop
6) when it exceeds the dividend portion, previous multiplier is the answer
7) repeat steps 3 to 5 until reaching to the end
I'd imagine that dividing the 'long' way like in grade school would be a potential route. I'm assuming you are receiving the original number as a string, so what you do is parse each digit. Example:
Step 0:
/-----------------
13 | 453453453435....
Step 1: "How many times does 13 go into 4? 0
0
/-----------------
13 | 453453453435....
Step 2: "How many times does 13 go into 45? 3
03
/-----------------
13 | 453453453435....
- 39
--
6
Step 3: "How many times does 13 go into 63? 4
etc etc. With this strategy, you can have any number length and only really have to hold enough digits in memory for an int (divisor) and double (dividend). (Assuming I got those terms right). You store the result as the last digit in your result string.
When you hit a point where no digits remain and the calculation wont go in 1 or more times, you return your result, which is already formatted as a string (because it could be potentially larger than an int).
The easiest division algorithm to implement for large numbers is shift and subtract.
if numerator is less than denominator then finish
shift denominator as far left as possible while it is still smaller than numerator
set bit in quotient for amount shifted
subtract shifted denominator from numerator
repeat
the numerator is now the remainder
The shifting need not be literal. For example, you can write an algorithm to subtract a left shifted value from another value, instead of actually shifting the whole value left before subtracting. The same goes for comparison.
Long division is difficult to implement because one of the steps in long division is long division. If the divisor is an int, then you can do long division fairly easily.
Knuth, Donald, The Art of Computer Programming, ISBN 0-201-89684-2, Volume 2: Seminumerical Algorithms, Section 4.3.1: The Classical Algorithms
You should probably try something like long division, but using computer words instead of digits.
In a high-level language, it will be most convenient to consider your "digit" to be half the size of your largest fixed-precision integer. For the long division method, you will need to handle the case where your partial intermediate result may be off by one, since your fixed-precision division can only handle the most-significant part of your arbitrary-precision divisor.
There are faster and more complicated means of doing arbitrary-precision arithmetic. Check out the appropriate wikipedia page. In particular, the Newton-Raphson method, when implemented carefully, can ensure that the time performance of your division is within a constant factor of your arbitrary-precision multiplication.
Unless part of your assignment was to be completely original, I would go with the algorithm I (and I assume you) were taught in grade school for doing large division by hand.

Accurate evaluation of 1/1 + 1/2 + ... 1/n row

I need to evaluate the sum of the row: 1/1+1/2+1/3+...+1/n. Considering that in C++ evaluations are not complete accurate, the order of summation plays important role. 1/n+1/(n-1)+...+1/2+1/1 expression gives the more accurate result.
So I need to find out the order of summation, which provides the maximum accuracy.
I don't even know where to begin.
Preferred language of realization is C++.
Sorry for my English, if there are any mistakes.
For large n you'd better use asymptotic formulas, like the ones on http://en.wikipedia.org/wiki/Harmonic_number;
Another way is to use exp-log transformation. Basically:
H_n = 1 + 1/2 + 1/3 + ... + 1/n = log(exp(1 + 1/2 + 1/3 + ... + 1/n)) = log(exp(1) * exp(1/2) * exp(1/3) * ... * exp(1/n)).
Exponents and logarithms can be calculated pretty quickly and accuratelly by your standard library. Using multiplication you should get much more accurate results.
If this is your homework and you are required to use simple addition, you'll better add from the smallest one to the largest one, as others suggested.
The reason for the lack of accuracy is the precision of the float, double, and long double types. They only store so many "decimal" places. So adding a very small value to a large value has no effect, the small term is "lost" in the larger one.
The series you're summing has a "long tail", in the sense that the small terms should add up to a large contribution. But if you sum in descending order, then after a while each new small term will have no effect (even before that, most of its decimal places will be discarded). Once you get to that point you can add a billion more terms, and if you do them one at a time it still has no effect.
I think that summing in ascending order should give best accuracy for this kind of series, although it's possible there are some odd corner cases where errors due to rounding to powers of (1/2) might just so happen to give a closer answer for some addition orders than others. You probably can't really predict this, though.
I don't even know where to begin.
Here: What Every Computer Scientist Should Know About Floating-Point Arithmetic
Actually, if you're doing the summation for large N, adding in order from smallest to largest is not the best way -- you can still get into a situation where the numbers you're adding are too small relative to the sum to produce an accurate result.
Look at the problem this way: You have N summations, regardless of ordering, and you wish to have the least total error. Thus, you should be able to get the least total error by minimizing the error of each summation -- and you minimize the error in a summation by adding values as nearly close to each other as possible. I believe that following that chain of logic gives you a binary tree of partial sums:
Sum[0,i] = value[i]
Sum[1,i/2] = Sum[0,i] + Sum[0,i+1]
Sum[j+1,i/2] = Sum[j,i] + Sum[j,i+1]
and so on until you get to a single answer.
Of course, when N is not a power of two, you'll end up with leftovers at each stage, which you need to carry over into the summations at the next stage.
(The margins of StackOverflow are of course too small to include a proof that this is optimal. In part because I haven't taken the time to prove it. But it does work for any N, however large, as all of the additions are adding values of nearly identical magnitude. Well, all but log(N) of them in the worst not-power-of-2 case, and that's vanishingly small compared to N.)
http://en.wikipedia.org/wiki/Arbitrary-precision_arithmetic
You can find libraries with ready for use implementation for C/C++.
For example http://www.apfloat.org/apfloat/
Unless you use some accurate closed-form representation, a small-to-large ordered summation is likely to be most accurate simple solution (it's not clear to me why a log-exp would help - that's a neat trick, but you're not winning anything with it here, as far as I can tell).
You can further gain precision by realizing that after a while, the sum will become "quantized": Effectively, when you have 2 digits of precision, adding 1.3 to 41 results in 42, not 42.3 - but you achieve almost a precision doubling by maintaining an "error" term. This is called Kahan Summation. You'd compute the error term (42-41-1.3 == -0.3) and correct that in the next addition by adding 0.3 to the next term before you add it in again.
Kahan Summation in addition to a small-to-large ordering is liable to be as accurate as you'll ever need to get. I seriously doubt you'll ever need anything better for the harmonic series - after all, even after 2^45 iterations (crazy many) you'd still only be dealing with a numbers that are at least 1/2^45 large, and a sum that's on the order of 45 (<2^6), for an order of magnitude difference of 51 powers-of-two - i.e. even still representable in a double precision variable if you add in the "wrong" order.
If you go small-to-large, and use Kahan Summation, the sun's probably going to extinguish before today's processors reach a percent of error - and you'll run into other tricky accuracy issues just due to the individual term error on that scale first anyhow (being that a number of the order of 2^53 or larger cannot be represented accurately as a double at all anyhow.)
I'm not sure about the order of summation playing an important role, I havent heard that before. I guess you want to do this in floating point arithmetic so the first thing is to think more inline of (1.0/1.0 + 1.0/2.0+1.0/3.0) - otherwise the compiler will do integer division
to determine order of evaluation, maybe a for loop or brackets?
e.g.
float f = 0.0;
for (int i=n; i>0; --i)
{
f += 1.0/static_cast<float>(i);
}
oh forgot to say, compilers will normally have switches to determine floating point evaluation mode. this is maybe related to what you say on order of summation - in visual C+ these are found in code-generation compile settings, in g++ there're options -float that handle this
actually, the other guy is right - you should do summation in order of smallest component first; so
1/n + 1/(n-1) .. 1/1
this is because the precision of a floating point number is linked to the scale, if you start at 1 you'll have 23 bits of precision relative to 1.0. if you start at a smaller number the precision is relative to the smaller number, so you'll get 23 bits of precision relative to 1xe-200 or whatever. then as the number gets bigger rounding error will occur, but the overall error will be less than the other direction
As all your numbers are rationals, the easiest (and also maybe the fastest, as it will have to do less floating point operations) would be to do the computations with rationals (tuples of 2 integers p,q), and then do just one floating point division at the end.
update to use this technique effectively you will need to use bigints for p & q, as they grow quite fast...
A fast prototype in Lisp, that has built in rationals shows:
(defun sum_harmonic (n acc)
(if (= n 0) acc (sum_harmonic (- n 1) (+ acc (/ 1 n)))))
(sum_harmonic 10 0)
7381/2520
[2.9289682]
(sum_harmonic 100 0)
14466636279520351160221518043104131447711/278881500918849908658135235741249214272
[5.1873775]
(sum_harmonic 1000 0)
53362913282294785045591045624042980409652472280384260097101349248456268889497101
75750609790198503569140908873155046809837844217211788500946430234432656602250210
02784256328520814055449412104425101426727702947747127089179639677796104532246924
26866468888281582071984897105110796873249319155529397017508931564519976085734473
01418328401172441228064907430770373668317005580029365923508858936023528585280816
0759574737836655413175508131522517/712886527466509305316638415571427292066835886
18858930404520019911543240875811114994764441519138715869117178170195752565129802
64067621009251465871004305131072686268143200196609974862745937188343705015434452
52373974529896314567498212823695623282379401106880926231770886197954079124775455
80493264757378299233527517967352480424636380511370343312147817468508784534856780
21888075373249921995672056932029099390891687487672697950931603520000
[7.485471]
So, the next better option could be to mantain the list of floating points and to reduce it summing the two smallest numbers in each step...