i'm a newbie using CPLEX Studio IDE 12.8.0 (built on eclipse), i'm trying to write my 1st model. i watched youtube videos and started coding an assignment workforce problem according to their tasks proficiency into 5 teams, i have 3 questions :
1-how to get rid of the errors,in the declaration of the objective function
// parameters
int n=...; //number of operators
int m=...; //number of tasks
int w=...; //number of teams
range operateurs= 1..n; //intervalle des opérateurs
range taches = 1..m; // varier les taches
range equipes = 1..w; // varier les équipes
int notation[operateurs][taches];
dvar boolean affectation[operateurs][taches][equipes];
**Maximize Sum (i in operateurs, j in taches, k in equipes) affectation[i][j][k]*notation[i][j];**
subject to {
forall (i in operateurs,j in taches)
unicite_aff_eq:
sum (k in equipes) affectation[i][j][k]== 1;
forall (k in equipes,i in operateurs)
unicite_aff_tache:
sum (j in taches)affectation[i][j][k]== 1;
forall (k in equipes,j in taches)
contenir_opp:
sum (i in operateurs) affectation[i][j][k]>= 1;
forall (i in operateurs,j in taches,k in equipes)
competence:
sum (i in operateurs,j in taches)
affectation[i][j][k]*notation[i][j]>=6;
}
2- can you give me a hand with modeling this constraint:
//constraint that i did not know to modele it
if (affectation[i][j][k]==1)
//at least there is notation[i][j]>=3;
here's the .dat file
n=56;
m=6;
w=5;
SheetConnection my_sheet ("affectation.xlsx");
notation from sheetread(my_sheet,"notation");
3-how can i make the declaration to import the notation table from excel.
i will be grateful if you can help me guys
thanks in advance
her's the error message that i get on the objective function declaration line (Maximize Sum (i in operateurs, j in taches, k in equipes) affectation[i][j][k]*notation[i][j];** )
//Description Ressource Chemin d'accès Emplacement Type
syntax error, unexpected (identifier), expecting ';' affectation-Opérateur.mod /affectation-Opérateur 20:59-67 C:/Users/ToualbiaMohamed Lies/opl/affectation-Opérateur/affectation-Opérateur.mod Problème de structure du modèle OPL//
with notation underlined in red.
so i wonder what i did wrong
and if it's possible tu multiply a matrix by a cube
(should make a declaration about the number of teams in the .dat file)
for 1) and 2) the following code works
// parameters
int n=2; //number of operators
int m=4; //number of tasks
int w=5; //number of teams
range operateurs= 1..n; //intervalle des opérateurs
range taches = 1..m; // varier les taches
range equipes = 1..w; // varier les équipes
int notation[o in operateurs][t in taches]=o*t mod 2;
dvar boolean affectation[operateurs][taches][equipes];
maximize sum (i in operateurs, j in taches, k in equipes) affectation[i][j][k]*notation[i][j];
subject to {
forall (i in operateurs,j in taches)
unicite_aff_eq:
sum (k in equipes) affectation[i][j][k]== 1;
forall (k in equipes,i in operateurs)
unicite_aff_tache:
sum (j in taches)affectation[i][j][k]== 1;
forall (k in equipes,j in taches)
contenir_opp:
sum (i in operateurs) affectation[i][j][k]>= 1;
forall (i in operateurs,j in taches,k in equipes)
competence:
sum (i in operateurs,j in taches)
affectation[i][j][k]*notation[i][j]>=6;
forall (i in operateurs,j in taches,k in equipes)
(affectation[i][j][k]==1)=> (notation[i][j]>=3);
}
for 3) in Making Decision optimization simple you could have a look at Excel spreadsheets
.mod
tuple param
{
int nbKids;
}
{param} params=...;
assert card(params)==1;
int nbKids=first(params).nbKids;
// a tuple is like a struct in C, a class in C++ or a record in Pascal
tuple bus
{
key int nbSeats;
float cost;
}
// This is a tuple set
{bus} buses=...;
// asserts help make sure data is fine
assert forall(b in buses) b.nbSeats>0;
assert forall(b in buses) b.cost>0;
// decision variable array
dvar int+ nbBus[buses];
// objective
minimize
sum(b in buses) b.cost*nbBus[b];
// constraints
subject to
{
sum(b in buses) b.nbSeats*nbBus[b]>=nbKids;
}
tuple result
{
key int nbSeats;
int nbBuses;
}
{result} results={<b.nbSeats,nbBus[b]> | b in buses};
.dat
SheetConnection s("zoo.xlsx");
params from SheetRead(s,"params!A2");
buses from SheetRead(s,"buses!A2:B3");
results to SheetWrite(s,"buses!E2:F3");
Related
I am solving this problem on CSES.
Given n planets, with exactly 1 teleporter on each planet which teleports us to some other planet (possibly the same), we have to solve q queries. Each query is associated with a start planet, x and a number of teleporters to traverse, k. For each query, we need to tell where we would reach after going through k teleporters.
I have attempted this problem using the binary lifting concept.
For each planet, I first saved the planets we would reach by going through 20, 21, 22,... teleporters.
Now, as per the constraints (esp. for k) provided in the question, we need only store the values till 231.
Then, for each query, starting from the start planet, I traverse through the teleporters using the data in the above created array (in 1) to mimic the binary expansion of k, the number of teleporters to traverse.
For example, if k = 5, i.e. (101)2, and the initial planet is x, I first go (001)2 = 1 planet ahead, using the array, let's say to planet y, and then (100)2 = 4 planets ahead. The planet now reached is the required result to the query.
Unfortunately, I am receiving TLE (time limit exceeded) error in the last test case (test 12).
Here's my code for reference:
#define inp(x) ll x; scanf("%lld", &x)
void solve()
{
// Inputting the values of n, number of planets and q, number of queries.
inp(n);
inp(q);
// Inputting the location of next planet the teleporter on each planet points to, with correction for 0 - based indexing
vector<int> adj(n);
for(int i = 0; i < n; i++)
{
scanf("%d", &(adj[i]));
adj[i]--;
}
// maxN stores the maximum value till which we need to locate the next reachable plane, based on constraints.
// A value of 32 means that we'll only ever need to go at max 2^31 places away from the planet in query.
int maxN = 32;
// This array consists of the next planet we can reach from any planet.
// Specifically, par[i][j] is the planet we get to, on passing through 2^j teleporters starting from planet i.
vector<vector<int>> par(n, vector<int>(maxN, -1));
for(int i = 0; i < n; i++)
{
par[i][0] = adj[i];
}
for(int i = 1; i < maxN; i++)
{
for(int j = 0; j < n; j++)
{
ll p1 = par[j][i-1];
par[j][i] = par[p1][i-1];
}
}
// This task is done for each query.
for(int i = 0; i < q; i++)
{
// x is the initial planet, corrected for 0 - based indexing.
inp(x);
x--;
// k is the number of teleporters to traverse.
inp(k);
// cur is the planet we currently are at.
int cur = x;
// For every i'th bit in k that is 1, the current planet is moved to the planet we reach to by moving through 2^i teleporters from cur.
for(int i = 0; (1 << i) <= k ; i++)
{
if(k & (1 << i))
{
cur = par[cur][i];
}
}
// Once the full binary expansion of k is used up, we are at cur, so (cur + 1) is the result because of the judge's 1 - based indexing.
cout<<(cur + 1)<<endl;
}
}
The code gives the correct output in every test case, but undergoes TLE in the final one (the result in the final one is correct too, just a TLE occurs). According to my observation the complexity of the code is O(32 * q + n), which doesn't seem to exceed the 106 bound for linear time code in 1 second.
Are there any hidden costs in the algorithm I may have missed, or some possible optimization?
Any help appreciated!
It looks to me like your code works (after fixing the scanf), but your par map could have 6.4M entries in it, and precalculating all of those might just get you over the 1s time limit.
Here are a few things to try, in order of complexity:
replace par with a single vector<int> and index it like par[i*32+j]. This will remove a lot of double indirections.
Buffer the output in a std::string and write it in one step at the end, in case there's some buffer flushing going on that you don't know about. I don't think so, but it's easy to try.
Starting at each planet, you enter a cycle in <= n steps. In O(n) time, you can precalculate the distance to the terminal cycle and the size of the terminal cycle for all planets. Using this information you can reduce each k to at most 20000, and that means you only need j <= 16.
I am solving a optimization problem using a european electric grid with 9241 nodes. To do that I created a connectivity matrix and inserted it in an Excel file. Using code from smaller problems (less nodes), which takes the information from the Excel file to write a CPLEX matrix, I tried to apply it to this bigger problem and I get the following error:
Exception from IBM ILOG Concert: Can not read data from excel. PEGASE-9241data.dat /Teste 8:36-37 E:\Program Files\IBM\ILOG\CPLEX_Studio129\opl\oplide\workspace\Teste\PEGASE-9241data.dat OPL Problem Marker
Some important things to know:
- The Excel file is .xlsx
- I wrote the connectivity matrix into the Excel file using Matlab (worked for smaller problems)
When I try the same code with a smaller problem (3120 nodes) It works fine.
Model:
range n = 1..9241;
dvar boolean x[n];
dvar boolean y[n][n];
//Conectivity matrix
int A[n][n] =...;
//Vector ZIB
int z[n] =...;
//Objective Function
dexpr int total = sum (p in n) x[p];
minimize (total);
subject to {
forall (i in n)
sum (j in n)
(A[i][j]*x[j] +A[i][j]*z[j]*y[i][j]) >= 1;
forall (j in n)
sum(i in n)
A[i][j]*y[i][j] == z[j];
}
Data:
SheetConnection sheet("E:\\Program Files\\IBM\\ILOG\\CPLEX_Studio129\\opl\\oplide\\workspace\\Teste\\PEGASEmatriz9241.xlsx");
A from SheetRead(sheet,"matriz9241");
z from SheetRead(sheet,"zib9241");
I think you have a memory issue. I managed to run the scalable example
https://www.ibm.com/developerworks/community/forums/html/topic?id=c2469c56-db27-4816-9cf2-f596513ce555&ps=25
til n=7000
So in your case I would divide your square into 4 squares. Let me share the full model to do that.
First to write into the Excel file in order to let you test.
.mod
execute
{
// http://cwestblog.com/2013/09/05/javascript-snippet-convert-number-to-column-name/
function toColumnName(num) {
for (var ret = '', a = 1, b = 26; (num -= a) >= 0; a = b, b *= 26) {
ret = String.fromCharCode(parseInt((num % b) / a) + 65) + ret;
}
return ret;
}
// 1,1 => A1 1,4 => D1 2,27 => AA2
function convertR1C1toA1(r,c)
{
return(toColumnName(c)+r);
}
}
int n=4;
int cell[i in 1..n][j in 1..n]=i*j;
int cell1[i in 1..n div 2][j in 1..n div 2]=cell[i][j];
int cell2[i in 1..n div 2][j in n div 2+1..n]=cell[i][j];
int cell3[i in n div 2+1..n][j in 1..n div 2]=cell[i][j];
int cell4[i in n div 2+1..n][j in n div 2+1 ..n]=cell[i][j];
string sheetWriteString1;
string sheetWriteString2;
string sheetWriteString3;
string sheetWriteString4;
execute
{
sheetWriteString1=convertR1C1toA1(1,1)+":"+convertR1C1toA1(n/2,n/2);
writeln("sheetWriteString1=",sheetWriteString1);
sheetWriteString2=convertR1C1toA1(1,n/2+1)+":"+convertR1C1toA1(n/2,n);
writeln("sheetWriteString2=",sheetWriteString2);
sheetWriteString3=convertR1C1toA1(n/2+1,1)+":"+convertR1C1toA1(n,n/2);
writeln("sheetWriteString3=",sheetWriteString3);
sheetWriteString4=convertR1C1toA1(n/2+1,n/2+1)+":"+convertR1C1toA1(n,n);
writeln("sheetWriteString4=",sheetWriteString4);
}
.dat
SheetConnection s("f2.xlsx");
cell1 to SheetWrite(s,sheetWriteString1);
cell2 to SheetWrite(s,sheetWriteString2);
cell3 to SheetWrite(s,sheetWriteString3);
cell4 to SheetWrite(s,sheetWriteString4);
and then in order to read f2.xls
.mod
int n=...;
string sheetWriteString1=...;
string sheetWriteString2=...;
string sheetWriteString3=...;
string sheetWriteString4=...;
int cell1[i in 1..n div 2][j in 1..n div 2]=...;
int cell2[i in 1..n div 2][j in n div 2+1..n]=...;
int cell3[i in n div 2+1..n][j in 1..n div 2]=...;
int cell4[i in n div 2+1..n][j in n div 2+1..n]=...;
int cell[i in 1..n][j in 1..n]=
(i<=n div 2)?((j<=n div 2)?cell1[i][j]:cell2[i][j]):((j<=n div 2)?cell3[i][j]:cell4[i][j]);
assert forall(i,j in 1..n) cell[i][j]==i*j;
.dat
SheetConnection s("f2.xlsx");
n=4;
sheetWriteString1="A1:B2";
sheetWriteString2="C1:D2";
sheetWriteString3="A3:B4";
sheetWriteString4="C3:D4";
cell1 from SheetRead(s,sheetWriteString1);
cell2 from SheetRead(s,sheetWriteString2);
cell3 from SheetRead(s,sheetWriteString3);
cell4 from SheetRead(s,sheetWriteString4);
So I need to solve for the linear system (A + i * mu * I) x = b, where A is dense Hermitian matrix (6x6 complex numbers), mu is a real scalar, and I is identity matrix.
Obviously if mu=0, I should just use Cholesky and be done with it. With non-zero mu though, the matrix ceases to be Hermitian and Cholesky fails.
Possible solutions:
Solve normal operator using Cholesky and multiply by the conjugate
Solve directly using LU decomposition
This is in a time-critical performance routine, where I need the most efficient method. Any thoughts on the optimum approach, or if there is a specific method for solving the above shifted Hermitian system?
This is to be deployed in a CUDA kernel, where I'll be solving many linear systems in parallel, e.g., one per thread. This means that I need a solution that minimizes thread divergence. Given the small system size, pivoting can be ignored without too much issue: this removes a possible source of thread divergence. I've already implemented an in-place Cholesky normal method, and while it's working ok, the performance isn't great in double precision.
I can't vouch for the stability of the method below, but if your matrix is reasonably well conditioned, it might be worth a try.
We want to solve
A*X = B
If we pick out the first row and column, say
A = ( a y )
( z A_ )
X = ( x )
( X_)
B = ( b )
( B_ )
The requirement is
a*x + y*X_ = b
z*x + A_*X_ = B_
so
x = (b - y*X_ )/a
(A_ - zy/a) * X_ = B_ - (b/a)z
The solution goes in two stages. First use the second equation to transform A and b, then use the second to form the solution x.
In C:
static void nhsol( int dim, complx* A, complx* B, complx* X)
{
int i, j, k;
complx a, fb, fa;
complx* z;
complx* acol;
// update A and B
for( i=0; i<dim; ++i)
{ z = A + i*dim;
a = z[i];
// update B
fb = B[i]/a;
for( j=i+1; j<dim; ++j)
{ B[j] -= fb*z[j];
}
// update A
for( k=i+1; k<dim; ++k)
{ acol = A + k*dim;
fa = acol[i]/a;
for( j=i+1; j<dim; ++j)
{ acol[j] -= fa*z[j];
}
}
}
// compute x
i = dim-1;
X[i] = B[i] / A[i+dim*i];
while( --i>=0)
{
complx s = B[i];
for( j=i+1; j<dim; ++j)
{ s -= A[i+j*dim]*X[j];
}
X[i] = s/A[i+i*dim];
}
}
where
typedef _Complex double complx;
If code space is not at a premuim it might be worth unrolling the loops. Personally I would do this by writing a program whose sole job was to write the code.
While practising problems from hackerearth I came across following problem( not from active contest ) and have been unsuccessful in solving it after many attempts.
Chandler is participating in a race competition involving N track
races. He wants to run his old car on these tracks having F amount of
initial fuel. At the end of each race, Chandler spends si fuel and
gains some money using which he adds ei amount of fuel to his car.
Also for participating in race i at any stage, Chandler should have
more than si amount of fuel. Also he can participate in race i once.
Help Chandler in maximizing the number of races he can take part in if
he has a choice to participate in the given races in any order.
How can I approach the problem. My approach was to sort by (ei-si) but than I couldn't incorporate condition that fuel present is greater than required for race.
EDIT I tried to solve using following algorithm but it fails,I also can't think of any inputs which fail the algorithm. Please help me out figuring whats wrong or give some input where my algorithm fails.
Sort (ei-si) in non-increasing order;
start iterating through sorted (ei-si) and find first element such that fuel>=si
update fuel=fuel+(ei-si);
update count;
erase that element from list, and start searching again;
if fuel was not updated than we can't take part in any races so stop searching
and output count.
EDIT And here is my code as requested.
#include<iostream>
#include<vector>
#include<algorithm>
#include<list>
using namespace std;
struct race{
int ei;
int si;
int earn;
};
bool compareByEarn(const race &a, const race &b)
{
return a.earn <= b.earn;
}
int main(){
int t;
cin>>t;
while(t--){
vector<struct race> fuel;
int f,n;
cin>>f>>n;
int si,ei;
while(n--){
cin>>si>>ei;
fuel.push_back({ei,si,ei-si});
}
sort(fuel.begin(),fuel.end(),compareByEarn);
list<struct race> temp;
std::copy( fuel.rbegin(), fuel.rend(), std::back_inserter(temp ) );
int count=0;
while(1){
int flag=0;
for (list<struct race>::iterator ci = temp.begin(); ci != temp.end(); ++ci){
if(ci->si<=f){
f+=ci->earn;
ci=temp.erase(ci);
++count;
flag=1;
break;
}
}
if(!flag){
break;
}
}
cout<<count<<endl;
}
}
EDIT As noted in answer below, the above greedy approach dosen't always work. So now any alternative method would be useful
Here is my solution, which gets accepted by the judge:
Eliminate those races which have a profit (ei>si)
Sort by ei (in decreasing order)
Solve the problem using a dynamic programming algorithm. (It is similar to a pseudo-polynomial solution for the 0-1 knapsack.)
It is clear that the order in which you eliminate profitable races does not matter. (As long as you process them until no more profitable races can be entered.)
For the rest, I will first prove that if a solution exists, you can perform the same set of races in decreasing order of ei, and the solution will still be feasible. Imagine we have a solution in which k races were chosen and let's say these k races have starting and ending fuel values of s1,...,sk and e1,...,ek. Let i be the first index where ei < ej (where j=i+1). We will show that we can swap i and i+1 without violating any constraints.
It is clear that swapping i and i+1 will not disrupt any constraints before i or after i+1, so we only need to prove that we can still perform race i if we swap its order with race i+1 (j). In the normal order, if the fuel level before we start on race i was f, after race i it will be f-si+ei, and this is at least sj. In other words, we have: f-si+ei>=sj, which means f-sj+ei>=si. However, we know that ei < ej so f-sj+ej >= f-sj+ei >= si, and therefore racing on the jth race before the ith race will still leave at least si fuel for race i.
From there, we implement a dynamic programming algorithm in which d[i][j] is the maximum number of races we can participate in if we can only use races i..n and we start with j units of fuel.
Here is my code:
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int maxn = 110;
const int maxf = 110*1000;
int d[maxn][maxf];
struct Race {
int s, e;
bool used;
inline bool operator < (const Race &o) const {
return e > o.e;
}
} race[maxn];
int main() {
int t;
for (cin >> t; t--;) {
memset(d, 0, sizeof d);
int f, n;
cin >> f >> n;
for (int i = 0; i < n; i++) {
cin >> race[i].s >> race[i].e;
race[i].used = false;
}
sort(race, race + n);
int count = 0;
bool found;
do {
found = 0;
for (int i = 0; i < n; i++)
if (!race[i].used && race[i].e >= race[i].s && race[i].s >= f) {
race[i].used = true;
count++;
f += race[i].s - race[i].e;
found = true;
}
} while (found);
for (int i = n - 1; i >= 0; i--) {
for (int j = 0; j < maxf; j++) {
d[i][j] = d[i + 1][j];
if (!race[i].used && j >= race[i].s) {
int f2 = j - race[i].s + race[i].e;
if (f2 < maxf)
d[i][j] = max(d[i][j], 1 + d[i + 1][f2]);
}
}
}
cout << d[0][f] + count << endl;
}
return 0;
}
You need to change your compareByEarn function
bool compareByEarn(const race &a, const race &b)
{
if(a.earn == b.earn) return a.si < b.si;
return a.earn < b.earn;
}
Above comparison means, choose the track with more earning (or lesser loss). But if there are 2 tracks with same earning, prefer the track which requires more fuel.
Consider the example
Initially fuel in the car = 4
track 1 : s = 2, e = 1
track 2 : s = 3, e = 2
track 3 : s = 4, e = 3
Expected answer = 3
Received answer = 2 or 3 depending on whether sorting algorithm is stable or unstable and the order of input\.
As a side note:
Also for participating in race i at any stage, Chandler should have
more than si amount of fuel
Should translate to
if(ci->si < f){ // and not if(ci->si<=f){
You can check if my observation is right or problem author chose incorrect sentence to describe the constraint.
EDIT With more reasoning I realized you can not do it with only greedy approach.
Consider the following input.
Initially fuel in the car = 9
track 1 : s = 9, e = 6
track 2 : s = 2, e = 0
track 3 : s = 2, e = 0
track 4 : s = 2, e = 0
Expected answer = 4
Received answer = 3
Is there any fast way to find the largest power of 10 smaller than a given number?
I'm using this algorithm, at the moment, but something inside myself dies anytime I see it:
10**( int( math.log10(x) ) ) # python
pow( 10, (int) log10(x) ) // C
I could implement simple log10 and pow functions for my problems with one loop each, but still I'm wondering if there is some bit magic for decimal numbers.
An alternative algorithm is:
i = 1;
while((i * 10) < x)
i *= 10;
Log and power are expensive operations. If you want fast, you probably want to look up the IEEE binary exponent in table to get the approximate power of ten, and then check if the mantissa forces a change by +1 or not. This should be 3 or 4 integer machine instructions (alternatively O(1) with a pretty small constant).
Given tables:
int IEEE_exponent_to_power_of_ten[2048]; // needs to be 2*max(IEEE_exponent)
double next_power_of_ten[600]; // needs to be 2*log10(pow(2,1024)]
// you can compute these tables offline if needed
for (p=-1023;p>1023;p++) // bounds are rough, see actual IEEE exponent ranges
{ IEEE_exponent_to_power_of_ten[p+1024]=log10(pow(2,p)); // you might have to worry about roundoff errors here
next_power_of_ten[log10(pow(2,p))+1024]=pow(10,IEEE_exponent_to_power_of_ten[p+1024]);
}
then your computation should be:
power_of_ten=IEEE_exponent_to_power_of_10[IEEE_Exponent(x)+1023];
if (x>=next_power_of_ten[power_of_ten]) power_of_ten++;
answer=next_power_of_ten[power_of_ten];
[You might really need to write this as assembler to squeeze out every last clock.]
[This code not tested.]
However, if you insist on doing this in python, the interpreter overhead may swamp the log/exp time and it might not matter.
So, do you want fast, or do you want short-to-write?
EDIT 12/23: OP now tells us that his "x" is integral. Under the assumption that it is a 64 (or 32) bit integer, my proposal still works but obviously there isn't an "IEEE_Exponent". Most processors have a "find first one" instruction that will tell you the number of 0 bits on the left hand (most significant) part of the value, e.g., leading zeros; you likely This is in essence 64 (or 32) minus the power of two for the value. Given exponent = 64 - leadingzeros, you have the power of two exponent and most of the rest of the algorithm is essentially unchanged (Modifications left for the reader).
If the processor doesn't have a find-first-one instruction, then probably the best bet is a balanced discrimination tree to determine the power of ten. For 64 bits, such a tree would take at most 18 compares to determine the exponent (10^18 ~~ 2^64).
Create an array of powers of 10. Search through it for the largest value smaller than x.
If x is fairly small, you may find that a linear search provides better performance than a binary search, due in part to fewer branch mis-predictions.
The asymptotically fastest way, as far as I know, involves repeated squaring.
func LogFloor(int value, int base) as int
//iterates values of the form (value: base^(2^i), power: 2^i)
val superPowers = iterator
var p = 1
var c = base
while c <= value
yield (c, p)
c *= c
p += p
endwhile
enditerator
//binary search for the correct power
var p = 0
var c = 1
for val ci, pi in superPowers.Reverse()
if c*ci <= value
c *= ci
p += pi
endif
endfor
return p
The algorithm takes logarithmic time and space in N, which is linear to N's representation size. [The time bound is probably a bit worse because I simplified optimistically]
Note that I assumed arbitrarily large integers (watch out for overflow!), since the naive times-10-until-over algorithm is probably fast enough when dealing with just 32-bit integers.
I think the fastest way is O(log(log(n))^2), the while loop takes O(log(log(n)) and it can be recursive call finite time (we can say O(c) where see is constant), first recursive call is takes log(log(sqrt(n))) time second takes .. and the number of sqrt in sqrt(sqrt(sqrt....(n)) < 10 is log(log(n)) and constant, because of machine limitations.
static long findPow10(long n)
{
if (n == 0)
return 0;
long i = 10;
long prevI = 10;
int count = 1;
while (i < n)
{
prevI = i;
i *= i;
count*=2;
}
if (i == n)
return count;
return count / 2 + findPow10(n / prevI);
}
In Python:
10**(len(str(int(x)))-1)
Given that this is language independent, if you can get the power of two that this number is significant to, eg y in x*2^y (which is the way the number is stored, though I'm not sure I have seen an easy way to access y in any language I have used) then if
z = int(y/(ln(10)/ln(2)))
(one floating point division)
10^z or 10^(z+1) will be your answer, though 10^z is still is not so simple (beg to be corrected).
I timed the methods with the following variations in C++ for the value a being a size_t type (inlining improves performance but does not change relative ordering).
Try 1: Multiply until find number.
size_t try1( size_t a )
{
size_t scalar = 1ul;
while( scalar * 10 < a ) scalar *= 10;
return scalar;
}
Try 2: Multiway if (could also be programmed using a lookup table).
size_t try2( size_t a )
{
return ( a < 10ul ? 1ul :
( a < 100ul ? 10ul :
( a < 1000ul ? 100ul :
( a < 10000ul ? 1000ul :
( a < 100000ul ? 10000ul :
( a < 1000000ul ? 100000ul :
( a < 10000000ul ? 1000000ul :
( a < 100000000ul ? 10000000ul :
( a < 1000000000ul ? 100000000ul :
( a < 10000000000ul ? 1000000000ul :
( a < 100000000000ul ? 10000000000ul :
( a < 1000000000000ul ? 100000000000ul :
( a < 10000000000000ul ? 1000000000000ul :
( a < 100000000000000ul ? 10000000000000ul :
( a < 1000000000000000ul ? 100000000000000ul :
( a < 10000000000000000ul ? 1000000000000000ul :
( a < 100000000000000000ul ? 10000000000000000ul :
( a < 1000000000000000000ul ? 100000000000000000ul :
( a < 10000000000000000000ul ? 1000000000000000000ul :
10000000000000000000ul )))))))))))))))))));
}
Try 3: Modified from findPow10 of #Saaed Amiri, which uses squaring to more rapidly find very large powers than Try 1.
size_t try3( size_t a )
{
if (a == 0)
return 0;
size_t i, j = 1;
size_t prev = 1;
while( j != 100 )
{
i = prev;
j = 10;
while (i <= a)
{
prev = i;
i *= j;
j *= j;
}
}
return prev;
}
Try 4: Lookup table indexed using count leading zeros instruction as per #Ira Baxter.
static const std::array<size_t,64> ltable2{
1ul, 1ul, 1ul, 1ul, 1ul, 10ul, 10ul, 10ul,
100ul, 100ul, 100ul, 1000ul, 1000ul, 1000ul,
1000ul, 10000ul, 10000ul, 10000ul, 100000ul,
100000ul, 100000ul, 1000000ul, 1000000ul,
1000000ul, 1000000ul, 10000000ul, 10000000ul,
10000000ul, 100000000ul, 100000000ul,
100000000ul, 1000000000ul, 1000000000ul,
1000000000ul, 1000000000ul, 10000000000ul,
10000000000ul, 10000000000ul, 100000000000ul,
100000000000ul, 100000000000ul, 1000000000000ul,
1000000000000ul, 1000000000000ul, 1000000000000ul,
10000000000000ul, 10000000000000ul, 10000000000000ul,
100000000000000ul, 100000000000000ul, 100000000000000ul,
1000000000000000ul, 1000000000000000ul, 1000000000000000ul,
1000000000000000ul, 10000000000000000ul, 10000000000000000ul,
10000000000000000ul, 100000000000000000ul, 100000000000000000ul,
100000000000000000ul, 100000000000000000ul, 1000000000000000000ul,
1000000000000000000ul };
size_t try4( size_t a )
{
if( a == 0 ) return 0;
size_t scalar = ltable2[ 64 - __builtin_clzl(a) ];
return (scalar * 10 > a ? scalar : scalar * 10 );
}
Timing is as follows (gcc 4.8)
for( size_t i = 0; i != 1000000000; ++i) try1(i) 6.6
for( size_t i = 0; i != 1000000000; ++i) try2(i) 0.3
for( size_t i = 0; i != 1000000000; ++i) try3(i) 6.5
for( size_t i = 0; i != 1000000000; ++i) try4(i) 0.3
for( size_t i = 0; i != 1000000000; ++i) pow(10,size_t(log10((double)i)))
98.1
The lookup/multiway-if beats everything in C++, but requires we know integers are a finite size. try3 is slower than try1 in this test for smaller values of the loop end value, for large numbers try3 beats try1. In python things are made difficult because integers are not limited so I would combine try2 with try3 to quickly process numbers up to a fixed limit then handle the possibly very large numbers.
In python I think lookup using a list comprehension is probably faster than a multiway-if.
# where we previously define lookuptable = ( 1, 10, 100, ..... )
scalar = [i for i in lookuptable if i < a][-1]