|
Jeremy, I know how to program, I've been doing it for 35 years. You are confusing a tired person making mistakes with a lack of knowledge and experience, and your comment is disrespectful towards someone you do not know.
I now realize from your last post that you are confusing a technical review with someone trashing you. In my post, I referred to code and the algorithm, not to you. And, at least one thing I wrote is correct.
All you had to write is, "your wrong, it works", and I would have re reviewed the code again, and realized my error. You actually did that with the issue of the return-type of the function, and I agreed immediately.
And, you wrote about improving performance. If you care about performance, I gave you some useful advice. I even offered the code. After looking the cycle times for the integer divide instruction for the Pentium IV processor mentioned in your article, I now realize that the algorithm I proposed would result in a huge speedup.
An 32-bit integer divide instruction takes about 387 cycles on an Intel X9650 processor. It's about the same number of cycles on both a 32-bit and the 64-bit architecture. Of course, caching issues and bus speeds are a factor for the speed of a program too, but based on that number of cycles, the algorithm in Seminumerical algorithms should be much faster than the divide algorithm used in the current code. And, the Pentium IV processor takes at least as many cycles as the 9650 for an integer divides, if not more.
The Pentium IV is a 32-bit processor, so it will take more than a single divide instruction to do a 64-bit divide.
On the more modern core i5 processors, an integer divide is about 40 cycles, so the algorithm you use might be fast enough on those. I suspect it will still be slower than the algorithm in the book, but I don't know that for sure. On a Pentium IV, the processor you mention in your article, the better algorithm will be significantly faster.
Again, it's the base 10 conversion algorithm in "Seminumerical Algorithms" by Donald Knuth.
If you want, I'll post the fast base 10 conversion code here, and it will drop right into your code with little change. I am not trashing you by doing that. I would never do that. I wouldn't have started and ended my initial post with "Nice job" if I meant to trash you.
Best wishes
modified 26-May-14 1:40am.
|
|
|
|
|
This is just a courtesy message to let you know I didn't read this nor will I. No longer wasting time on it. Have a nice life.
Jeremy Falcon
|
|
|
|
|
For anyone else who uses this code, beware of these two issues. Jeremy, I really do hope you read this so you fix the code.
-------------------------------------------------
The following number overruns the array szWord.
-7,777,777,777,777,777,777
This is within range of a signed 64-bit values.
The array szWord to contain the output string before it is copied to the passed buffer is currently 225 character in length. (I redownloaded the code, and double-checked that I didn't bump the keyboard and change this - it is 225). I also viewed the rendered text in the debugger.
char szWord[225] = {0};
The program doesn't crash with this value when I run the program, but I do get the wrong output text. An array overrun might act differently with different compilers, so you might or might not get the same result, but the array is definitely too short for the correct string, which is:
"negative seven quintillion seven hundred seventy-seven quadrillion seven hundred seventy-seven trillion seven hundred seventy-seven billion seven hundred seventy-seven million seven hundred seventy-seven thousand seven hundred seventy-seven"
That string is 240 characters long. (That text is from a different program - so the words are not capitalized).
--------------------------------------------------
The value "900" with ordinal set to true produces the string:
Nine Hundred
It should be:
Nine Hundredth
If there is one or three ending zeros in the final three digits, ordinals work, it doesn't work when there are two zeros at the end of the number.
modified 5-Jun-14 20:42pm.
|
|
|
|
|
|
Yup, that's me. Always been a programmer, but in the past couple of years took up acting. Which is awesome.
Jeremy Falcon
|
|
|
|
|
|
Yeah, I decided make an update and join last year an add 64-bit support.
|
|
|
|
|
how to represent 1000.25 ????
Ninety-eight percent of the thrill comes from knowing that the thing you designed works, and works almost the way you expected it would. If that happens, part of you is in that machine.
|
|
|
|
|
renjith_sree wrote: how to represent 1000.25 ????
Since floating point operations can be slower than unsigned integer ones, I decided the best thing to do is not implement the decimal point conversion. However, this can be easily achieved in code by breaking a part the integral portions before and after the decimal place and calling GetNumWord() twice.
|
|
|
|
|
So, my question is: can you give us the function you wrote in PHP? I would love to incorprate this into a site I'm working on.
|
|
|
|
|
Nah, it's long since gone. However, you can still use the C program over the web. How, exactly did you want to implement this?
Jeremy Falcon
|
|
|
|
|
Hmm... I'm not terribly familiar with C. Would it work on a Unix box?
Very simply, a site I run has an article series feature. That is, multiple articles are grouped together. At the beginning of each article, I'm doing a mysql_num_rows and dynamically assigning a page number to each article. Then I am printing the page number on the article: "This is article #4 of the X series."
So, I would like for the opening line of the article to say: "This is the fourth article in the X series." That's all I wanted to use it for.
|
|
|
|
|
Well, first and foremost. Do you have shell access to your site? That is, can you Telnet and/or SSH to it?
Jeremy Falcon
|
|
|
|
|
|
Sorry it took so long to get back to you on this.
But, if you have SSH access you'll need to take the existing code and make a CGI program out of it (so it'll return its output to STDOUT) and compile it on the server. Then, the simplest way to implement it into your site would be to use a SSI call to it.
Jeremy Falcon
|
|
|
|
|
1. You should try to use a nice string lib.
There are so many around (at this codeproject)
So you will overcome many buffer stuff.
2. Try to modulize the actual text to support another language.
E.x : Store
single num English French VietNamese
4 , "four" , "quatre" , "bon"
3. I don't know what algorith you are using but take a look at mine NumToText Excel macro at
www.coderfarm.com/pubs/Excel
I "steal" that code somewhere I can't remember.
Nguyen Binh.
|
|
|
|
|
Thanks for the suggestions, but my primary goal with this was to keep things simple and fast, something wich a robust string library make make it slower.
Also, do not prefer to use "stolen" code as you put it. I believe in always giving credit where it's do.
Jeremy Falcon
|
|
|
|
|
You missed my Idea. I donot convert any typed data to their textual but a string pointer.
|
|
|
|
|
Here's your prototype:
char *getNumCardinal (char *szDest, unsigned long num, short isProper, short isAnd);
You indicate szDest needs to be passed in, fine... However, consider the following code:
char buffer[3];
getNumCardinal (buffer,12,TRUE,TRUE);
That just caused a buffer overwrite, because you wrote "twelve\0" into my 3-byte buffer. That's no good. Not at all. You need to either use a string class (which manages it's own internal buffer), or have the caller pass in the length of the string he has allocated.
Look up some references on the usage of strcpy vs. strncpy. It's essentially the same problem, and I can't believe noone here pointed it out...
|
|
|
|
|
Anonymous wrote:
That just caused a buffer overwrite, because you wrote "twelve\0" into my 3-byte buffer. That's no good. Not at all.
The intent was that the caller would have enough sense to allocate a proper buffer. How many times do you see in MS documentation that the behavior is "undefined" unless you do something the way it's expected?
Regardless, you do serve a valid point that I will take into consideration. But, who am I to give credit to for the tip? I always give credit where it's do. If you prefer to stay anonymous, no problem, I just won't be able to give you credit.
Thanks!
Jeremy L. Falcon<nobr>
Homepage : Sonork = 100.16311
"Victims falling under chains ~ You hear them crying dying pains
The fist of terrors breaking through ~ Now there's nothing you can do"
Song: Phantom Lord - Album: Kill 'em All - Artist: Metallica
|
|
|
|
|
You return values by using strdup(). It should be noted that strdup() is a common extension, but not in the ANSI standard (you meantion that ANSI compliance is important). Further, it gets it memory via malloc, which means that the returned value needs to be free'd or a memory leak will occur. Usage like you do in your demo:
printf("\nProper Cardinal:\n%s\n\nCardinal:\n%s\n\nProper Ordinal:\n%s\n\nOrdinal:\n%s\n\n",
getNumWord(x, TRUE, FALSE),
getNumWord(x, FALSE, FALSE),
getNumWord(x, TRUE, TRUE),
getNumWord(x, FALSE, TRUE));
guarantees a memory leak.
Truth,
James
|
|
|
|
|
Yeah, I just checked it out in MSDN and sure enough it isn't. It's amazing how you can get so used to something. I have used strdup() on other systems as well, I guess it slipped my mind after a while.
Either way, I'll make another update. I sent a second update last week but it hasn't been uploaded yet. Now I know why the unedited contributions are becoming popular. I'll make a third update real soon, and hope it gets online pronto.
Thanks for the tip!
Jeremy L. Falcon
"The One Who Said, 'The One Who Said...'"
<nobr>
Homepage : Feature Article : Sonork = 100.16311
|
|
|
|
|
Jeremy Falcon wrote:
Now I know why the unedited contributions are becoming popular
hey! I heard that! :P
cheers,
Chris Maunder
|
|
|
|
|
I didn't think you were watching!
Jeremy L. Falcon
"The One Who Said, 'The One Who Said...'"
<nobr>
Homepage : Feature Article : Sonork = 100.16311
|
|
|
|
|
Hello
A colleague tell me about Jeremy Falcon interger to text code. I already developed an interger to text for my project. My prog is far more better cos I can convert "double" number, not only interger. It means you can convert a number of 40 digits or more ?
Even It can convert negative and decimal number with scale of 2. Please try my code
P/s (it is used for vietnamese)
extern "C" NUMANALYSE_API char *VS_MainNum(char *numstr)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
CString ret("");
double x;
char *stopstring;
//char frac[20];
CString cstmp("");
int d;
int itmp;
int decimal, sign;
int signall;
char *buffer;
d = 0;
signall = 0;
if ((x = strtod( numstr, &stopstring )) == HUGE_VAL )
return("NG Error overflow");
*stopstring = '\0';
ret.Format("%s", numstr);
if (x <0)
signall = 1;
itmp = ret.Find('.');
if ( itmp != -1)
{
cstmp = ret.Right(ret.GetLength() - itmp - 1);
cstmp = cstmp.Left(2);
d = atoi(cstmp);
ret = ret.Left(itmp);
}
if ((x = strtod( ret, &stopstring )) == HUGE_VAL )
return("NG Error overflow");
buffer = _fcvt( x, 0, &decimal, &sign );
if (sign != 0)
x = -x ;
decimal = strlen(buffer);
strcpy(buffer,ret.Right(decimal));
ret = NumComb( x, buffer);
ret.TrimLeft(" ");
ret.TrimRight(" ");
if (d != 0)
ret = ret + " point " + Fractal(cstmp);
if (signall != 0)
ret = "minus " + ret;
ret = "OK " + ret;
strcpy(g_ConvStr,ret);
return(g_ConvStr) ;
}
CString Fractal(CString cstw)
{
CString two("");
int dz;
int unt;
int il;
int tw;
il = cstw.GetLength();
tw = atoi(cstw);
dz = tw/10;
unt = tw%10;
if ( il == 1)
return(unit_arr[tw]);
else
if ( tw < 10 )
{
two.Format("%s %s",unit_arr[0],unit_arr[tw]);
return(two);
}
else
if ( unt == 0 )
return(unit_arr[dz]);
switch ( dz )
{
case 1:
switch ( unt )
{
case 5:
two.Format("%s %s",unit_arr[10],unit_arr[12]);
break;
case 0:
two.Format("%s",unit_arr[10]);
break;
default:
two.Format("%s %s",unit_arr[10],unit_arr[unt]);
}
break;
case 0:
two.Format("%s %s",unit_arr[0],unit_arr[unt]);
break;
default:
switch ( unt )
{
case 5:
two.Format("%s %s",unit_arr[dz],unit_arr[11]);
break;
case 0:
two.Format("%s %s",unit_arr[dz],sup_arr[0]);
break;
case 1:
two.Format("%s %s",unit_arr[dz],unit_arr[14]);
break;
case 4:
two.Format("%s %s",unit_arr[dz],unit_arr[15]);
break;
default:
two.Format("%s %s",unit_arr[dz],unit_arr[unt]);
}
break;
}
return(two);
}
CString NumComb(double x, char *s)
{
int it;
CString numall;
CString stemp(s);
CString ct(s);
int ilen;
int im;
if (x == 0)
return(unit_arr[(int)x]);
ilen = stemp.GetLength();
im = ilen%3;
stemp = ct.Left(im);
it = atoi(stemp);
switch ( im )
{
case 1:
numall.Format("%s",unit_arr[(int)it]);
break;
case 2:
numall = FirstTwo((int)it);
break;
}
if (ilen == 3 )
{
numall = FirstThree((int)x);
return(numall);
}
im = ilen - im;
ct = ct.Right(im);
int z;
z=4;
BOOL bt;
bt=TRUE;
while ( im > 0 )
{
stemp = ct.Left(3);
it = atoi(stemp);
if ( z == 4)
{
z = (im /3)%3;
if (z == 0)
z = 3;
}
if (it == 0)
{
if (bt)
{
if (numall != "")
numall = " " + numall + " " + sup_arr[(z + 1)] ;
}
im -= 3;
ct = ct.Right(im);
z = (im /3)%3;
if (z == 0)
z = 3;
if (z == 3)
bt = TRUE;
else
bt = FALSE;
continue;
}
if (bt)
if (numall != "")
{
numall = " " + numall + " " + sup_arr[(z + 1)] + " "+ FirstThree(it);
}
else
numall = FirstThree(it);
else
if (numall != "")
{
numall = " " + numall + " " + FirstThree(it);
}
else
numall = FirstThree(it);
im -= 3;
ct = ct.Right(im);
z = (im /3)%3;
if (z == 0)
z = 3;
bt=TRUE;
}
return(numall);
}
CString FirstThree(int th)
{
CString three;
if (th == 0)
{
three ="";
return(three);
}
if ( ( th%100 ) == 0 )
three.Format("%s %s",unit_arr[th/100],sup_arr[1]);
else
three.Format("%s %s %s",unit_arr[th/100],sup_arr[1],FirstTwo(th%100));
return(three);
}
CString FirstTwo(int tw)
{
CString two;
int dz;
int unt;
dz = tw/10;
unt = tw%10;
switch ( dz )
{
case 1:
switch ( unt )
{
case 5:
two.Format("%s %s",unit_arr[10],unit_arr[12]);
break;
case 0:
two.Format("%s",unit_arr[10]);
break;
default:
two.Format("%s %s",unit_arr[10],unit_arr[unt]);
}
break;
case 0:
two.Format("%s %s",unit_arr[13],unit_arr[unt]);
break;
default:
switch ( unt )
{
case 5:
two.Format("%s %s",unit_arr[dz],unit_arr[11]);
break;
case 0:
two.Format("%s %s",unit_arr[dz],sup_arr[0]);
break;
case 1:
two.Format("%s %s",unit_arr[dz],unit_arr[14]);
break;
case 4:
two.Format("%s %s",unit_arr[dz],unit_arr[15]);
break;
default:
two.Format("%s %s",unit_arr[dz],unit_arr[unt]);
}
break;
}
return(two);
}
Where should I go tomorow?
From Vietnam
|
|
|
|
|