Base converter with fractions?
|
01-15-2017, 05:53 AM
Post: #1
|
|||
|
|||
Base converter with fractions?
One of my favorite RPL programs is called BASECALC by Ian Matthew Smith. It not only converts numbers from any base to any other base (not just the usual 4 bases but ANY base 2 through 62), but it even supports fractions (not just whole numbers). So, for example, it converts pi to "3.3DC9FINE" in base 25. And it has a nice user interface.
Has anybody written a base converter for the HP Prime which handles fractions and non-standard bases like BASECALC does? <0|ɸ|0> -Joe- |
|||
01-22-2017, 03:13 PM
Post: #2
|
|||
|
|||
RE: Base converter with fractions?
Hello Joe,
I have not written a program, but it is not so difficult to get pi in hexadecimal form, with digits after the point. In Home settings choose 64 for number of bits. Then multiply pi with 16^8, and subsequently divide it by 16^8. Multiplying gives:13493037704.5 ROUND(13493037704.5,0)= 13493037705 R→B(13493037705)=#3243F6A89h Dividing this by 16^8 is equivalent to moving the point by 8 positions, which gives: #3.243F6A89h |
|||
01-22-2017, 11:22 PM
Post: #3
|
|||
|
|||
RE: Base converter with fractions?
Thanks, Jan. That's pretty much how my "hex" program works: http://www.hpmuseum.org/forum/thread-720.html
But my "hex" program only works in base 16 (obviously). So I guess what I need to do is generalize that program by changing the hard-coded "16" to be a variable. The fraction expansion for CAS values can be expressed exactly for any base that is an exact power of 2, but all other bases will need to stop at some arbitrary number of digits. Smith's BASECALC sets the number of fraction digits to IP(12/log10(base)). Prime's CAS might allow a higher value than 12 without losing accuracy. A perfect programming mini-challenge on this rainy day! <0|ɸ|0> -Joe- |
|||
01-26-2017, 12:38 PM
Post: #4
|
|||
|
|||
RE: Base converter with fractions?
When I would like to express 3.142 in base 7, I would do the following.
Multiplication with 7^4 gives: 7543.942 Rounded this is: 7544 Now I am going to express this integer number in base 7: Division of 7544 by 7^4 (=2401) gives 3+rest 341 Division of 341 by 7^3 (=343) gives 0+rest 341 Division of 341 by 7^2 (49) gives 6+rest 47 Division of 47 by 7 gives 6+ rest 5. So 7544=3*7^4+0*7^3+6*7^2+6*7+5 and therefore 7544=30665_base7 In the beginning we multiplied with 7^4, so now we have to divide again by 7^4, which shifts the point by 4 positions, and thus gives: 3.142=3.0665_base7 |
|||
01-26-2017, 05:18 PM
(This post was last modified: 01-26-2017 05:18 PM by Joe Horn.)
Post: #5
|
|||
|
|||
RE: Base converter with fractions?
(01-26-2017 12:38 PM)Jan_D Wrote: When I would like to express 3.142 in base 7, I would do the following. Unfortunately that amount of initial roundoff introduces a great amount of error. Smith's BASECALC converts 3.142 (decimal) to "3.06646410512335" (base 7), which it converts cleanly back to what we started with, namely 3.142 (decimal), whereas "3.0665" (base 7) converts to 3.1420241566 (decimal), which is not what we started with. Multiplying by a greater power of 7 at the beginning helps achieve greater accuracy, but even using 7^13 (which turns 3.142 into an integer in a 12-digit machine) doesn't yield a result as accurate as BASECALC's. I guess it's time to explore Smith's method. It might be objected that the input only had four significant digits, so the output should be rounded off accordingly. But that's not necessarily true; a user might intend that input to mean "exactly 3.142", as if they had input 3.14200000000 with the trailing zeros being significant digits. HP's philosophy has never been to round outputs to the number of significant digits of the input, because only the user knows the input's number of significant digits. HP's philosophy has always been, "Assume that the user's input is exactly what they want it to be, and let them adjust the accuracy of the result if they want to." IMHO all HP calculator software should follow that philosophy. <0|ɸ|0> -Joe- |
|||
01-26-2017, 06:57 PM
(This post was last modified: 01-26-2017 07:35 PM by Han.)
Post: #6
|
|||
|
|||
RE: Base converter with fractions?
Here's the math for this specific example. A general program is left as an exercise for the diligent reader.
3.142 = 3 + 0.142 Convert the whole number part into base 7. Since it is only 3, then we are done. This leaves 0.142 for conversion to \( 0.d_1 d_2 d_3 \dotsm \) where the \( d_i \) are 0 through 6. Note that if we multiply the fractional part by 7 then we will get a value that is non-negative and strictly less than 7. \[ \begin{align*} 0.142 & = 0.d_1 d_2 d_3 \dotsm \\ 7\cdot 0.142 & = d_1 + 0.d_2 d_3 d_4 \dotsm\\ 0.994 & = d_1 + 0.d_2 d_3 d_4 \dotsm \\ \end{align*} \] Therefore \( d_1 = 0 \). Now repeat... \[ \begin{align*} 0.994 & = 0. d_2 d_3 d_4 \dotsm \\ 7\cdot 0.994 & = d_2 + 0.d_3 d_4 d_5 \dotsm\\ 6.958 & = d_2 + 0.d_3 d_4 d_5 \dotsm \\ \end{align*} \] Therefore \( d_2 = 6 \). Rinse and repeat (subtract the integer part and repeat for the fractional part) for as many digits as you need. There should be no round-off error when using BCD math (until you get to bases where the "digits" are represented by more than a single numeral in base 10 -- hence the \( 12/\log_{10}(b) \) limitation), but you might possibly be off using the HP Prime's base-2 representation of floating points. EDIT: For those who just want the answer: The integer portion of a number can be converted to various bases using known methods. The "hard" part is the fractional portion. However, the fraction portion \( d \) is always such that \( 0 \le d < 1 \). So if \( b \) is the base, then \( 0 \le bd < b \). If \( 0.d_1 d_2 d_3 \dotsm \) is the base-\(b\) representation of \(d \), then \( bd\) is \( d_1 + 0.d_2 d_3 d_4 \dotsm \). Hence \( d_1 \) is the integer part of \( bd \). Graph 3D | QPI | SolveSys |
|||
01-27-2017, 04:37 AM
(This post was last modified: 01-27-2017 12:24 PM by Han.)
Post: #7
|
|||
|
|||
RE: Base converter with fractions?
Purposely avoided using the CAS directly so that I could use a "random" variable, resulting in code that does not read well.
EDIT: fixed some bugs Code: EXPORT basecalc() I'm sure there is another method using numer() and denom() rather than ip(). Basically, enter your integer as n, along with the presumed base1. The program converts n written in base1 into base2 representation, and sets up the program to re-run it in the opposite direction. Hit CANCEL or press ON to stop. Graph 3D | QPI | SolveSys |
|||
01-27-2017, 05:00 AM
Post: #8
|
|||
|
|||
RE: Base converter with fractions?
(01-26-2017 05:18 PM)Joe Horn Wrote: Unfortunately that amount of initial roundoff introduces a great amount of error. Smith's BASECALC converts 3.142 (decimal) to "3.06646410512335" (base 7), which it converts cleanly back to what we started with, namely 3.142 (decimal), whereas "3.0665" (base 7) converts to 3.1420241566 (decimal), which is not what we started with. It appears that the back-conversion to 3.142 is only "clean" due to rounding (limited number of significant digits). Graph 3D | QPI | SolveSys |
|||
01-28-2017, 03:25 AM
Post: #9
|
|||
|
|||
RE: Base converter with fractions?
Thanks, Han! Great program!
(01-27-2017 05:00 AM)Han Wrote:(01-26-2017 05:18 PM)Joe Horn Wrote: Unfortunately that amount of initial roundoff introduces a great amount of error. Smith's BASECALC converts 3.142 (decimal) to "3.06646410512335" (base 7), which it converts cleanly back to what we started with, namely 3.142 (decimal), whereas "3.0665" (base 7) converts to 3.1420241566 (decimal), which is not what we started with. That's correct. BASECALC uses ordinary floating-point reals for base 10 numbers, which in RPL means that they are rounded to 12 significant digits. <0|ɸ|0> -Joe- |
|||
01-28-2017, 01:42 PM
Post: #10
|
|||
|
|||
RE: Base converter with fractions?
(01-26-2017 06:57 PM)Han Wrote: Here's the math for this specific example. A general program is left as an exercise for the diligent reader. Nice and efficient math, Han! |
|||
01-28-2017, 02:58 PM
Post: #11
|
|||
|
|||
RE: Base converter with fractions?
I think your desired programme does the same (?) as this 50g programme
http://www.hpmuseum.org/forum/thread-7675.html if you have the divisor set to 1. |
|||
01-28-2017, 03:15 PM
(This post was last modified: 01-28-2017 03:27 PM by Dieter.)
Post: #12
|
|||
|
|||
RE: Base converter with fractions?
(01-26-2017 05:18 PM)Joe Horn Wrote: Unfortunately that amount of initial roundoff introduces a great amount of error. Sure. The example rounds to four decimal places, so the result of course is not correct in all 12 digits, let alone the exact answer. (01-26-2017 05:18 PM)Joe Horn Wrote: Smith's BASECALC converts 3.142 (decimal) to "3.06646410512335" (base 7), which it converts cleanly back to what we started with, namely 3.142 (decimal), FTR: this still is not the exact result, it's just the first 15 digits. The exact base-7 representation of 3,142 is periodic, it's \(3,\overline{06646410512335362252}\). Since we're in a museum here: one of my first books on RPN and calculators included an HP67/97 program for base conversions, both for integer and fractional numbers. The method has been posted here: simply multiply the fractional part by the base, then the integer part of this is the next digit. I just noticed that this book is available on Google books (Helmut Alt, Anwendung programmierbarer Taschenrechner Band 1). If you read German: it's page 140ff. Dieter |
|||
02-02-2017, 05:26 PM
(This post was last modified: 02-02-2017 05:29 PM by Jan_D.)
Post: #13
|
|||
|
|||
RE: Base converter with fractions?
(01-27-2017 04:37 AM)Han Wrote: I'm sure there is another method using numer() and denom() rather than ip(). Yes, that is true. Instead of IP(x) we can use iquo(numer(x),denom(x)) (easy to find in Toolbox menu: CAS -Integer - Division - Quotient) When x=999999999999999/1000000000000000 the first method returns 1 and the second method gives the correct result 0. You found a smart way to correct it though, in a smart program! |
|||
02-03-2017, 01:51 PM
Post: #14
|
|||
|
|||
RE: Base converter with fractions?
(01-27-2017 04:37 AM)Han Wrote: Purposely avoided using the CAS directly so that I could use a "random" variable, resulting in code that does not read well. I slightly modified your program, not because it is not good enough but to make it better readable. Instead of a CAS variable like tmp586605323013 it uses the CAS variable tmp. Code:
|
|||
02-03-2017, 02:31 PM
Post: #15
|
|||
|
|||
RE: Base converter with fractions?
Just a bit of info on why I used a "random" CAS variable. I personally believe that any program should do whatever it can to preserve the state of the machine it runs on. This means leaving variables in tact where possible, restoring user settings to their original state prior to running the program, etc. Because 'tmp' could very well be a user variable (in fact, I use it a lot while doing CAS-related things), this program would over-write the user's content. On the other hand, it would be very unlikely that there is a user variable named something like tmp164503545498 (certainly too long to be user friendly, and the random digits makes a name collision highly unlikely). That was the driving factor behind using the random variable -- I can still use a CAS variable (which is necessary) without worrying too much about destroying the user's CAS variables.
Graph 3D | QPI | SolveSys |
|||
02-03-2017, 05:52 PM
Post: #16
|
|||
|
|||
RE: Base converter with fractions?
When we consider the program as a black box your code is certainly more professional than my simplified one.
But when we are interested in understanding the program, and possibly modify it, I prefer the other. It should not be a problem that we reserve one CAS variable, say tmp or ex1, ex2, for use of programs, there are enough variables left. Built - in apps like the Function app or Advanced Graphing also change the content of X and Y, which could be considered more serious. The advantage of this is however that by doing this they can very effectively collaborate with e.g. the Solve app. |
|||
02-13-2017, 01:14 PM
Post: #17
|
|||
|
|||
RE: Base converter with fractions?
Like Han pointed out in one of his good and important articles:
HP Prime CAS programming it is also possible to write his program with the help of a CAS – helpprogram. This could be the code: Code:
Disadvantage of this method, though the code is easier, is that cashelpprogram() is not a local program. Suppose that we had already written another program which also uses a Cas program with the name cashelpprogram(), then this would not affect the working of our program, but when we would execute the earlier program again it would not work properly anymore because it would use the most recent version of cashelpprogram(), and in order to let it work properly again we would have to recompile it. This can be done easily though, by opening it in the Program Catalog and leaving it again. So when we forget to do this it can cause unexpected problems. |
|||
02-13-2017, 01:27 PM
Post: #18
|
|||
|
|||
RE: Base converter with fractions?
In such a case I recommend using a unique identifier such as casbasecalc() to avoid reusing the same name.
Graph 3D | QPI | SolveSys |
|||
02-13-2017, 02:36 PM
(This post was last modified: 02-13-2017 02:37 PM by toml_12953.)
Post: #19
|
|||
|
|||
RE: Base converter with fractions?
(02-03-2017 02:31 PM)Han Wrote: Just a bit of info on why I used a "random" CAS variable. I personally believe that any program should do whatever it can to preserve the state of the machine it runs on. This means leaving variables in tact where possible, restoring user settings to their original state prior to running the program, etc. Because 'tmp' could very well be a user variable (in fact, I use it a lot while doing CAS-related things), this program would over-write the user's content. On the other hand, it would be very unlikely that there is a user variable named something like tmp164503545498 (certainly too long to be user friendly, and the random digits makes a name collision highly unlikely). That was the driving factor behind using the random variable -- I can still use a CAS variable (which is necessary) without worrying too much about destroying the user's CAS variables. To me, tmp or temp mean a temporary variable. I never care about the value of a temporary variable after the program using it ends. If I did want to preserve the value, I'd put it in a less temporary-sounding variable! (Don't ask about temperature! ) I guess that's why I make almost all the variables in a program LOCAL so they disappear after the program ends. I do save the angle mode and other state-related variables if my program alters any of them. Tom L Tom L Cui bono? |
|||
02-21-2017, 05:59 PM
Post: #20
|
|||
|
|||
RE: Base converter with fractions?
(02-03-2017 01:51 PM)Jan_D Wrote: I slightly modified your program, not because it is not good enough but to make it better readable. It is also possible to make the program completely local, without using a global CAS variable tmp, and still do the calculations in CAS. We can declare a local variable tmp, and the program will work with this local variable and use it for CAS calculations. The only thing we have to pay attention to is that it is not allowed to use square brackets, but we have to use parentheses. So instead of CAS("tmp[1]:=tmp[1]+d*b1^k") we have to write CAS("tmp(1):=tmp(1)+d*b1^k"). Instead of CAS("tmp(1):=tmp(1)+d*b1^k") we could also write: tmp(1):=CAS(“tmp(1)+d*b1^k"). Code:
|
|||
« Next Oldest | Next Newest »
|
User(s) browsing this thread: 3 Guest(s)