Discussion:
problem with keygen
(too old to reply)
Starglider 4
2010-04-15 23:13:51 UTC
Permalink
i've got a basic function to generate a list of product activation codes,
into a .txt file:

const int no_keys=200;
int keys[no_keys],key_start=0;
double key_fac=7415379421725.7259638214256;

void make_keylist()
{

int _x;
double fac_=key_fac,_y;

for(int i=0;i<no_keys;i++)
{
_x=i+key_start+1;
_y=double(_x)*fac_;
_y=abs(_y);
// while(_y>=1000000.0)_y-=1000000.0;
keys[i]=int(_y);
}

char co[80];
FILE *stream;

fopen_s(&stream,"keylist.txt","w");

for(int i=0;i<no_keys;i++)
{
_x=keys[i];
_itoa_s(_x,co,80,10);
char *co2=strcat(co,"\n");
fwrite(co2,sizeof(char),strlen(co2),stream);
}

fclose(stream);

}

the problem is that the resulting .txt file displays a list
of 200 of exactly the same negative codes.
i really don't understand what i'm doing wrong here.
please help me out.

MK
John H.
2010-04-16 15:42:05 UTC
Permalink
Post by Starglider 4
the problem is that the resulting .txt file displays a list
of 200 of exactly the same negative codes.
On VC 6.0, I ran the code you posted (except swapped out the _s
functions for their older equivalent) and it made a .txt with a bunch
of different entries.
Starglider 4
2010-04-16 17:43:34 UTC
Permalink
Ok! so it works, with deprecated itoa's?
Post by John H.
Post by Starglider 4
the problem is that the resulting .txt file displays a list
of 200 of exactly the same negative codes.
On VC 6.0, I ran the code you posted (except swapped out the _s
functions for their older equivalent) and it made a .txt with a bunch
of different entries.
John H.
2010-04-16 20:48:28 UTC
Permalink
 _y=abs(_y);
With abs, you don't always get what you expect.
ISO C offers "int abs(int num)" and "double fabs(double num)". Some C+
+ implementations offer an overloaded version of abs: "double
abs(double num)". I am guessing that when you call "abs": the version
you were using takes an int parameter, so your 64-bit double _y was
getting converted to a 32-bit integer when passed into abs, returned
as a 32-bit integer, and then that was getting converted back to a 64-
bit double.

There might be a way to get a C++ "double abs(double)", but I'm not
quite sure. I think the sure thing is to #include <cmath> and use the
"double fabs(double)".
Starglider 4
2010-04-17 16:39:35 UTC
Permalink
My problem is not with the abs().
I suspect it's inside the file generation loop.

Have you got some other suggestions/solutions, or anybody else please?

I don't actually understand, why the code runs perfectly
with your system. I've already tried to set the _s functions
back to the older ones, but it doesn't actually
help.
Post by Starglider 4
_y=abs(_y);
With abs, you don't always get what you expect.
ISO C offers "int abs(int num)" and "double fabs(double num)". Some C+
+ implementations offer an overloaded version of abs: "double
abs(double num)". I am guessing that when you call "abs": the version
you were using takes an int parameter, so your 64-bit double _y was
getting converted to a 32-bit integer when passed into abs, returned
as a 32-bit integer, and then that was getting converted back to a 64-
bit double.

There might be a way to get a C++ "double abs(double)", but I'm not
quite sure. I think the sure thing is to #include <cmath> and use the
"double fabs(double)".
John H.
2010-04-19 15:39:45 UTC
Permalink
Post by Starglider 4
My problem is not with the abs().
I suspect it's inside the file generation loop.
Have you got some other suggestions/solutions, or anybody else please?
As Eckhardt pointed out, I think you are running into numerical
problems, and the length of ints and doubles. In general, a 32-bit
can't hold the same range of numbers as a 64-bit double. This is what
I was getting at with the abs suggestion, but the problem might be
elsewhere. A couple things you might try:

- Use the version of an integer number that is 64-bit. I can't
remember what it is in VC++, but you might try "long long" or
"int64_t". I think this would work, but the range of even a 64-bit
integer is probably different than that of a 64-bit floating.

- Stick with doubles through out the function (e.g. make keys an array
of doubles, etc.). If it is important that keys only contains whole
numbers, you can use a truncation function.

For both of those alternatives, you might have to look at a
replacement for _itoa_s, since that is designed to work with int.
Ulrich Eckhardt
2010-04-19 14:26:04 UTC
Permalink
Post by John H.
Post by Starglider 4
_y=abs(_y);
With abs, you don't always get what you expect.
ISO C offers "int abs(int num)" and "double fabs(double num)". Some C+
+ implementations offer an overloaded version of abs: "double
abs(double num)". I am guessing that when you call "abs": the version
you were using takes an int parameter, so your 64-bit double _y was
getting converted to a 32-bit integer when passed into abs, returned
as a 32-bit integer, and then that was getting converted back to a 64-
bit double.
Actually, C++ offers several overloads of std::abs(), including some for
floating-point types. Whether the actual implementation supports that of
course depends, but any modern C++ compiler should support those.

Uli
--
C++ FAQ: http://parashift.com/c++-faq-lite

Sator Laser GmbH
Geschäftsführer: Thorsten Föcking, Amtsgericht Hamburg HR B62 932
Ulrich Eckhardt
2010-04-19 14:41:49 UTC
Permalink
Post by Starglider 4
i've got a basic function to generate a list of product activation codes,
const int no_keys=200;
int keys[no_keys],key_start=0;
double key_fac=7415379421725.7259638214256;
Those are 26 significant decimal digits, which require around 85 binary
digits. You probably only have 52, so this value is already rounded off!
Post by Starglider 4
int _x;
double fac_=key_fac,_y;
for(int i=0;i<no_keys;i++)
{
_x=i+key_start+1;
_y=double(_x)*fac_;
_y=abs(_y);
// while(_y>=1000000.0)_y-=1000000.0;
keys[i]=int(_y);
}
In this loop, when assigning to keys[i], you convert a double value to an
int. An int has a maximum value of ~2,000,000,000, so unless _x is smaller
than 1, the value of _x*fac_ will overflow the int. The only possible value
of _x smaller than 1 is 0, which -if I understand your code correctly- will
never occur. I actually don't know what an implementation is supposed to do
when such a conversion fails, but I don't think any particular behaviour is
guaranteed.
Post by Starglider 4
char co[80];
FILE *stream;
fopen_s(&stream,"keylist.txt","w");
for(int i=0;i<no_keys;i++)
{
_x=keys[i];
_itoa_s(_x,co,80,10);
char *co2=strcat(co,"\n");
fwrite(co2,sizeof(char),strlen(co2),stream);
}
You could use fprintf(co, "%d\n", keys[i]); here. Further, sizeof is defined
in multiples of the size of a char, which hence by definition is one. ;)
Post by Starglider 4
the problem is that the resulting .txt file displays a list
of 200 of exactly the same negative codes.
i really don't understand what i'm doing wrong here.
The problem is that whichever algorithm you wanted to implement here, you
probably didn't, because the numerics are wrong.

Uli
--
C++ FAQ: http://parashift.com/c++-faq-lite

Sator Laser GmbH
Geschäftsführer: Thorsten Föcking, Amtsgericht Hamburg HR B62 932
Starglider 4
2010-04-19 18:24:26 UTC
Permalink
So it comes down to an overflow and subsequent
undefined behaviour?

Any good resources on undefined behaviour?

Thanks,

MK
Post by Ulrich Eckhardt
Post by Starglider 4
i've got a basic function to generate a list of product activation codes,
const int no_keys=200;
int keys[no_keys],key_start=0;
double key_fac=7415379421725.7259638214256;
Those are 26 significant decimal digits, which require around 85 binary
digits. You probably only have 52, so this value is already rounded off!
Post by Starglider 4
int _x;
double fac_=key_fac,_y;
for(int i=0;i<no_keys;i++)
{
_x=i+key_start+1;
_y=double(_x)*fac_;
_y=abs(_y);
// while(_y>=1000000.0)_y-=1000000.0;
keys[i]=int(_y);
}
In this loop, when assigning to keys[i], you convert a double value to an
int. An int has a maximum value of ~2,000,000,000, so unless _x is smaller
than 1, the value of _x*fac_ will overflow the int. The only possible value
of _x smaller than 1 is 0, which -if I understand your code correctly- will
never occur. I actually don't know what an implementation is supposed to do
when such a conversion fails, but I don't think any particular behaviour is
guaranteed.
Post by Starglider 4
char co[80];
FILE *stream;
fopen_s(&stream,"keylist.txt","w");
for(int i=0;i<no_keys;i++)
{
_x=keys[i];
_itoa_s(_x,co,80,10);
char *co2=strcat(co,"\n");
fwrite(co2,sizeof(char),strlen(co2),stream);
}
You could use fprintf(co, "%d\n", keys[i]); here. Further, sizeof is defined
in multiples of the size of a char, which hence by definition is one. ;)
Post by Starglider 4
the problem is that the resulting .txt file displays a list
of 200 of exactly the same negative codes.
i really don't understand what i'm doing wrong here.
The problem is that whichever algorithm you wanted to implement here, you
probably didn't, because the numerics are wrong.
Uli
--
C++ FAQ: http://parashift.com/c++-faq-lite
Sator Laser GmbH
Geschäftsführer: Thorsten Föcking, Amtsgericht Hamburg HR B62 932
Ulrich Eckhardt
2010-04-20 07:07:44 UTC
Permalink
Post by Starglider 4
So it comes down to an overflow and subsequent
undefined behaviour?
Probably. The first problem though is that I have no idea how your algorithm
is supposed to work, which makes it nigh impossible to implement it in any
programming language.
Post by Starglider 4
Any good resources on undefined behaviour?
The ISO C standard.

Uli
--
C++ FAQ: http://parashift.com/c++-faq-lite

Sator Laser GmbH
Geschäftsführer: Thorsten Föcking, Amtsgericht Hamburg HR B62 932
Loading...