Say you have a number like 5.03; what would be the best way to determine the total number of digits in that?
It could be done with a while loop, like this:

Code:

//N=5.03
While fPart(N
10N->N
End
//N=503
1+int(log(N->N
//N=3

But Tari mentioned in #cemetech that it could be done with logarithms. Any ideas? This is the IRC discussion
SAX/IRC wrote:
10:37:25 (C) KermMartian: 1+int(log(iPart(N)))...?
10:37:48 (C) KermMartian: Or do you need the number of digits after the decimal point too?
10:38:30 (C) M. I. Wright: Yeah, those are important (hence the while loop that I mentioned earlier; would that be the fastest way to do it?)
10:39:05 (#) Tari: you can do it with logarithms
10:39:21 (#) Tari: something along the lines of log10(n)^-1
10:39:31 (#) Tari: and probably a ceiling in there somewhere
10:40:25 (#) Tari: log10(fPart(n)) that is
10:40:37 (C) M. I. Wright: huh. Haven't gotten to logarithms in math yet (although I understand what they do, I don't know how to use them)
10:40:39 (#) Tari: for the number of digits in the fractional part of n
10:41:36 (C) KermMartian: Wouldn't that only give you the position of the first nonzero digit in the fractional part?
10:41:49 (C) KermMartian: Rather than the position of the last digit, which is more what he wants?
10:41:58 (C) KermMartian: fPart(0.123) gives you .123, not 123.
10:42:35 (#) Tari: simple example which I'm working with, say 1.11
10:42:36 (C) M. I. Wright: If you raise it to the power -1 I think it works?
10:42:50 (#) Tari: log10(0.11)^-1 = -1.04
10:43:08 (#) Tari: ceiling(-1 * -1.04) = 2 digits
10:43:23 (#) calc84: wouldn't it be about the same for 1.1111111 though?
10:43:33 (C) KermMartian: Yes
10:43:34 (C) KermMartian: I think so too
10:43:39 (#) Tari: yeah, that's no good
10:44:00 (C) KermMartian: ~give M. I. Wright topic
I have the solution: Very Happy Very Happy Very Happy

Code:

5.2394
21-sum(seq(int(10^X*fPart(Ans))=10^X*fPart(Ans),X,1,20

or better:

Code:

21-sum(seq(not(fPart(Ans*10^X)),X,1,20
PT_ wrote:
I have the solution: Very Happy Very Happy Very Happy

Code:

5.2394
21-sum(seq(int(10^X*fPart(Ans))=10^X*fPart(Ans),X,1,20


That's really interesting! Tari did mention that it could be done with logarithms, though, so I wonder if there's another solution...
This is by far the best one I have seen. I actually use this in organizing a file system type program.

Here is the code by Weregoose:

Code:
sum(0 xor fPart(Ans10^(cumSum(not(binompdf(14,0
Electromagnet8 wrote:
This is by far the best one I have seen. I actually use this in organizing a file system type program.

Here is the code by Weregoose:

Code:
sum(0 xor fPart(Ans10^(cumSum(not(binompdf(14,0


Yes, I was just looking at this thread and thinking "I'm a number theorist by training: I should be able to come up with something here", when your post arrived. Weregoose's method is way beyond brilliant!
Brilliant indeed--I love binomcdf( and binompdf(. Here's a token-by-token explanation (I was going to say line-by-line but it's only one line). Let's say your number is 1.337:

Ans-->X
binompdf(14,0 creates creates a list that is a 1 followed by 14 0's. See http://tibasicdev.wikidot.com/binompdf for why. A maximum of 14 digits can be stored in any z80 BASIC float, so a list longer than this is unnecessary.
not(Ans makes this a 0 followed by 14 1's.
cumsum(Ans makes it {0,1,2,...,14}
X10^Ans makes that {1.337,13.37,133.7,1337,13370,...}
fPart(Ans) returns {.337,.37,.7,0,0,0,...}
0 xor Ans returns 1 if Ans is nonzero, and 0 if Ans is zero. "0 or Ans" and "not(not(Ans" do the same thing, but not(not( is slower.
Then sum( counts the number of nonzero terms. Since there are three decimal places, the number will have a fractional part until it it's multiplied by 10^3. So 1.337 times 10^{0, 1, and 2} will have a fractional part. This is three terms, so 3 is returned.
Electromagnet8 wrote:
This is by far the best one I have seen. I actually use this in organizing a file system type program.

Here is the code by Weregoose:

Code:
sum(0 xor fPart(Ans10^(cumSum(not(binompdf(14,0


lirtosiast wrote:
Brilliant indeed--I love binomcdf( and binompdf(. Here's a token-by-token explanation (I was going to say line-by-line but it's only one line). Let's say your number is 1.337:

Ans-->X
binompdf(14,0 creates creates a list that is a 1 followed by 13 0's. See http://tibasicdev.wikidot.com/binompdf for why. A maximum of 14 digits can be stored in any z80 BASIC float, so a list longer than this is unnecessary.
not(Ans makes this a 0 followed by 13 1's.
cumsum(Ans makes it {0,1,2,...,13}
X10^Ans makes that {1.337,13.37,133.7,1337,13370,...}
fPart(Ans) returns {.337,.37,.7,0,0,0,...}
0 xor Ans returns 1 if Ans is nonzero, and 0 if Ans is zero. "0 or Ans" and "not(not(Ans" do the same thing, but not(not( is slower.
Then sum( counts the number of nonzero terms. Since there are three decimal places, the number will have a fractional part until it it's multiplied by 10^3. So 1.337 times 10^{0, 1, and 2} will have a fractional part. This is three terms, so 3 is returned.


Oh wow, that's genius! I'll definitely be using this, although I'll have to add 2+int(log(X)) to count the decimal point and non-fractional digits.
lirtosiast wrote:
Brilliant indeed--I love binomcdf( and binompdf(. Here's a token-by-token explanation (I was going to say line-by-line but it's only one line). Let's say your number is 1.337:[...]
I salute you for not just agreeing that another user's solution is a good one, but actually taking the time to turn it into a learning opportunity and explaining how it works.
So after some experimentation (a whole minute of it!), I arrived at
Code:
sum(0 xor iPart(Ans10^(-cumSum(not(binompdf(14,0

which is equal to 1+int(log(Ans)) (but slower). Would there be any way to combine the above formula with Weregoose's to make one that'd give the total amount of digits in a number?

Edit: I've shortened it to

Code:

cumSum(not(binompdf(14,0
sum(0 xor iPart(N10^(-Ans))+fPart(N10^(Ans

but I'm positive it can be optimized further.
Kerm: I'll always acknowledge Weregoose's brilliance. Back in 2010 when that was written, it was sheer wizardry, because the cumsum(binomcdf( trick was relatively unknown. (I think Weregoose may have invented it, but I can't find the post right now. Maybe it's in the UTI archives?)
M. I. Wright: I can't think of a way off the top of my head.

EDIT: M. I. Wright: That doesn't actually work, but if it did it could be optimized to

Code:

//does not work either
10^(cumSum(not(binompdf(14,0
sum(iPart(N/Ans) or fPart(NAns
If you had your number as Ans, you could run:
10^(fPart(log(Ans))-1
to reduce it to pure decimal, then run Weregoose's routine.

E.g. 48.735 would become 0.48735 after the above instruction.

WARNING: I haven't tested whether this would work reliably. There is clearly a possibility that rounding errors in the log - antilog part of the calculation would introduce some stray decimal digits that weren't in your original number, and blow the whole idea out of the water!
Rather interestingly, all of these solutions are iterative- it seems like there's not a way to do this in truly constant time.

Even if we were to directly inspect the float representation, you'd have to perform a O(ndigits) scan of the mantissa to find the number of trailing zeros, which yields the desired result when added to the exponent.
OldMathTeacher wrote:
If you had your number as Ans, you could run:
10^(fPart(log(Ans))-1
to reduce it to pure decimal, then run Weregoose's routine.

E.g. 48.735 would become 0.48735 after the above instruction.

WARNING: I haven't tested whether this would work reliably. There is clearly a possibility that rounding errors in the log - antilog part of the calculation would introduce some stray decimal digits that weren't in your original number, and blow the whole idea out of the water!

Oh, of course. I'd forgotten that log() tricks could be used since we're working with iParts, hah.
Youre correct that it doesn't seem to work all the time, though; running it with, for instance, 2.001 returns 1.001 :/
Would perhaps something like N/10^(1+int(log(N work?
M. I. Wright wrote:
OldMathTeacher wrote:
If you had your number as Ans, you could run:
10^(fPart(log(Ans))-1
to reduce it to pure decimal, then run Weregoose's routine.

E.g. 48.735 would become 0.48735 after the above instruction.

WARNING: I haven't tested whether this would work reliably. There is clearly a possibility that rounding errors in the log - antilog part of the calculation would introduce some stray decimal digits that weren't in your original number, and blow the whole idea out of the water!

Oh, of course. I'd forgotten that log() tricks could be used since we're working with iParts, hah.
Youre correct that it doesn't seem to work all the time, though; running it with, for instance, 2.001 returns 1.001 :/
Would perhaps something like N/10^(1+int(log(N work?

I tried it with 2.001 and got 0.2001 as expected. Are you copying the parentheses exactly?
OldMathTeacher wrote:
M. I. Wright wrote:
OldMathTeacher wrote:
If you had your number as Ans, you could run:
10^(fPart(log(Ans))-1
to reduce it to pure decimal, then run Weregoose's routine.

E.g. 48.735 would become 0.48735 after the above instruction.

WARNING: I haven't tested whether this would work reliably. There is clearly a possibility that rounding errors in the log - antilog part of the calculation would introduce some stray decimal digits that weren't in your original number, and blow the whole idea out of the water!

Oh, of course. I'd forgotten that log() tricks could be used since we're working with iParts, hah.
Youre correct that it doesn't seem to work all the time, though; running it with, for instance, 2.001 returns 1.001 :/
Would perhaps something like N/10^(1+int(log(N work?

I tried it with 2.001 and got 0.2001 as expected. Are you copying the parentheses exactly?

Oh, whoops, I had three parentheses after the number. It works for all the numbers I've tried/need to try for my project, so it's probably a better idea to do this than to attempt to combine the two equations like I was. Thanks for this!
So do we have, for the number of digits in any negative or positive number less than 10^14,

Code:
(0 xor fPart(Ans))+(Ans<0)+sum(0 xor fPart(round(10^(cumSum(binomcdf(14,0))-2+fPart(log(abs(Ans
?
Wait, I think the round(, which is necessary to prevent rounding errors in the last four digits, may cut off some digits...

I guess the code is, using the N/10^(int(log(N method:

Code:
(0 xor fPart(Ans))+(Ans<0)+sum(0 xor fPart(Ans10^(cumSum(binomcdf(14,0))-2-int(log(abs(Ans

Is this right?
Wait, what about the leading 0 before a decimal point? Do we count it?
lirtosiast wrote:
So do we have, for the number of digits in any negative or positive number,

Code:
(0 xor fPart(Ans))+(Ans<0)+sum(0 xor fPart(round(10^(cumSum(binomcdf(14,0))-2+fPart(log(abs(Ans
?
Wait, I think the round(, which is necessary to prevent rounding errors in the last four digits, may cut off some digits...

I guess the code is, using the N/10^(int(log(N method:

Code:
(0 xor fPart(Ans))+(Ans<0)+sum(0 xor fPart(Ans10^(cumSum(binomcdf(14,0))-2-int(log(Ans

Is this right?
Wait, what about the leading 0 before a decimal point? Do we count it?


Surely, if Ans < 0, the

Code:
log(Ans
part of your code will generate an Error anyway. If you need it to accept negative numbers, why not use
Code:
Abs(Ans
first?
Oh, good catch. Edited.
OldMathTeacher wrote:
If you had your number as Ans, you could run:
10^(fPart(log(Ans))-1
to reduce it to pure decimal, then run Weregoose's routine.


Interesting. The TI-OS appears not to treat the number produced from this output like a regular decimal. If Ans=23.79, running this produces .2379... but if you then run Weregoose's routine on that, the output is 14. Omitting the sum(0 xor from the routine gets this list:


Code:
{.2379,.379,.79,.9,2E-10,2E-9,2E-8,2E-7,2E-6,2E-5,2E-4,.002,.02,.2,0}
M. I. Wright, that's a rounding error in the 10^(log()) calculation (it's off by, I think, 10^-12), as OldMathTeacher said earlier. Using Ans10^(-int(log(Ans instead eliminates the error entirely.
  
Register to Join the Conversation
Have your own thoughts to add to this or any other topic? Want to ask a question, offer a suggestion, share your own programs and projects, upload a file to the file archives, get help with calculator and computer programming, or simply chat with like-minded coders and tech and calculator enthusiasts via the site-wide AJAX SAX widget? Registration for a free Cemetech account only takes a minute.

» Go to Registration page
Page 1 of 2
» All times are UTC - 5 Hours
 
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

 

Advertisement