Comparison to HP calculators
ND1 follows the HP calculator model for mixed RPN/algebraic calculators, specifically HP’s RPL line. The keys and menus look mostly like a HP-28S, but the innards are most comparable to a HP-50g. On top of HP features, it transparently adds many of its own unique features.
With “transparently” we mean, that these additions do not change or impact the functionality that is being added to.
For example, ND1 adds data types like Code, Image, Color, ChemFormula to the traditional set of data types found in HP calculators. It adds JavaScript and concepts like “code injection”. But these extensions don’t change how a user works with the calculator following the HP model.
Similarly, it extends the usability of data types, notably of vectors and matrices: you can apply any single-valued function (such as SIN) to a vector or matrix, when you cannot do this with HP calculators. Having support for some of these extensions is very much in the spirit of those calculators, and would probably be found in a future HP model.
Transparent extensions may also enrich or augment functionality without adding an altogether new feature. For example, with ND1 you can calculate the quadrillionth Fibonacci number via [[0 1][1 1]] 1000000000000000 MODPOW, when you can’t do this with a HP-50g, which sports the same MODPOW function, but not the range.
Similarly, while ND1 allows you to compute factorials just like on an HP (via FACT or “!”), you can also just type “33!” on the edit line to do the computation. While HP calculators wouldn’t allow this, it transparently adds to the user experience.
ND1 supports RPL on the language level of the HP-50g, and it pushes beyond with RPL+. It’s the only non-HP calculator we know that can run many HP-50g programs. It does *not* implement the full command set of the HP-50g. We will successively add HP-50g commands. The intention is to have it run most User RPL programs, so that ND1 can deeply dig into the large pools of available HP-28, -48, -49, -50g programs. Conversion of transcode sequences (\<<, \->, etc.) exists on data import, and many of your existing programs should run without changes.
It is very important to point out that ND1 lacks what the above-mentioned calculators were famous for: ND1 does not (yet) have a built-in CAS (Computer Algebra System). It has limited support for symbolic math with expressions, and it has a mechanism to pass on solving, isolation, differentiation, integration and Taylor to WolframAlpha™ and display results–but it does not internally support such functions of higher math.
While ND1 lacks a CAS, it does things–thanks to its speed, available memory, and support for JavaScript and MorphEngine–that go well beyond what is meant to be done on a “calculator”: like displaying fractals in real-time.
ND1 aims to be a great type-rich everyday scientific/graphing calculator, and a calculator that sports great programmability. But it’s meant to be used alongside a CAS for people who need symbolic and higher math.
JavaScript in a calculator is something that no HP calculator supports, and it’s a big deal, we think. It gives programmers a very dynamic and powerful language and ND1’s MorphEngine provides an API that supports math applications. You don’t need to know “client-side” (Web-oriented) JavaScript to use it. If you know C, you will productively program ND1 in JavaScript in no time.
Even if you don’t plan on programming with JavaScript, the language provides functions and data types that you can benefit from, both as a user and as a RPL programmer. For example, ND1 features an Image data type that you can use to create and display gray and color images. You can use the Image type in RPL and you won’t even know that it is, in fact, a JavaScript object. You can call any JavaScript function from RPL, and it will look like a normal RPL command. Likewise, you can call any RPL program from JavaScript, and it will look like a JavaScript function.
Enjoying much faster hardware, ND1 is hundreds of times faster than a HP-28 or HP-48. It is also still 10-100 times faster than a HP-50g. It also features higher precision. Our RPL byte-code compiler is more efficient than an 49-series emulator running on the same hardware. See the benchmark section below for timing results.
Getting data in and out of your calculator is much easier in ND1 than with any HP calc. You tap download or upload, or type email, and you’re done. You can edit your data on your computer and move it back in. There’s a concept of “Shared Folders” which allows one-tap sharing of folders with all users of ND1 and ND0 (the free version).
The remainder of this document lists some of the transparent additions, and notable lacking features, in ND1 in comparison with the above-mentioned HP calculators, and a conclusion. An appendix provides benchmark results.
Overview
(c) 2011-2012 Naive Design. All rights reserved.
You could say ND1’s baseline is a re-implementation of the HP-28S calculator.
The key layout in Classic mode, the structure of the menu system, the supported data types, and the basic operational principles are almost identical.
The HP-28S was the first calculator that introduced object-oriented types, RPL, and a CAS.
As mentioned above, ND1 does not feature a CAS (and HP-28S’s, to be fair, was the first, but is not up to today’s standards), so it
-lacks the Algebra menu
-repurposes the functions in the SOLV menu (which now go out to WolframAlpha™ for better answers)
ND1 also lacks some less important things:
-the CATALOG
-“file system” functions or multiple levels of depth in folders
-interactive RPL commands (to get keys; do custom menus; display text or pixels)
-internal calculator flags (though it has functions to set/recall flags)
It does add, transparently:
-display is bigger; more lines: you can see 4 - 21 lines, plus edit line, plus soft keys; wider: 3x3 matrix viewable with 5 digits after the point, instead of 2; edit line expands to 6-8 lines for writing code
- fits 8 chars in soft-key instead of 4-5
-always shows edit line and soft-keys, also when doing graphics; this permit to change drawing parameters while displaying graph, for example
- some better results: e^(i*π)+1 == 0 returns "true"; tan(π/2) returns Infinity; etc.
- symbolic expressions as matrix and vector elements
-any single-valued function can be applied to a vector or matrix to work on every element
- many commands are richer or operate on more types: e.g., POS and SUB defined for matrices, vector + any appends any to vector
- any RPL program can be used as "user function"; i.e., it doesn’t have to start with the arrow (->) operator
- option for expressions as args, and still getting fully evaluated result when running RPL (e.g., dist_rpl with 'sin((3,4))' as one arg); HP28 will return expression that needs to be manually evaluated
- literal vectors and matrices in expressions, e.g., '[[3,4],[6,7]]*√π'
- RPL programs in Algebraic expressions, not only algebraic RPL programs that return one arg (but note that no argument count check will take place)
- can enter and use expressions involving vectors and matrices; (e.g., eval an expression like "[[3,e],[e,7]] * [2,e]")
- better error msgs: e.g., in a multi-arg invocation "bad index" instead of "bad arg"
- will allow a vector of vectors and result in an array
- can use short and long names for units, e.g. 'in' or 'Inch'
- conversions: can define user conversions, change existing conversions, provide RPL programs for conversions
- SWAP can be used in algebraic expressions
(This is not the complete list. There’re more things that have been added or improved.)
In addition to transparent additions, ND1 has its own list of completely new features, as listed under Specifications. These will not be repeated here. It shall suffice to mention that running JavaScript programs, having access to an HTML5 Canvas and networking, supporting types like BigInts and Image, does allow completely different, and very powerful, things to be done with ND1, in comparison to a HP-28S.
If you loved the HP-28S, you will be the happiest of users of the ND1. It will almost feel as if it was made for you. We still encourage you to switch from Classic to Modern mode, after you found your bearings. You will like the improved ergonomics of the keypad and having 50% more soft-keys.
Why did we base ND1 on the HP-28S and not on the HP-48? The HP-28S is the purer of the two, and the better place to start, we felt. Its two-sided key layout transported very well to iPhone / iPod touch, where space is at a premium, but a standard keyboard exists that plays very well the role of the left side of keys. We did not want to have keys that are crammed or have more than two functions on them (HP-48 has four); we also didn’t want to have a menu system that requires users to descend one extra level before they arrive at the functions they’re looking for.
Compared to the HP-28S
The HP-48 added a bigger display and substantial features to the HP-28S, it’s immediate predecessor.
The substantial features were mostly in the domain of its CAS. As ND1 doesn’t have a CAS, you may find a lot of features missing, if you’re a heavy user of those functions.
If you used the HP-48 mainly for non-higher and symbolic math, you should still be happy with ND1, as it operates very similarly to the HP-48, for non-CAS functionality, and ND1 gives you many HP-49/50g features.
Most items in the list of transparent additions above, apply to the HP-48 as well.
The biggest improvements would be symbolic vectors and matrices, the screen (bigger and much higher-resolution for both stack display and graphics mode), “parallel list processing,” and the much easier way to get information onto the edit line (you can simply type using the standard iOS keyboard, instead of awkwardly hunting for keys).
You may need some getting used to the shallower menu system (one level, instead of two) and its slightly different organization, but we hope that you will ultimately find it easier to navigate.
ND1 features various of the HP-48 additions that do not relate to CAS functionality. For example, there are →V2, →V3, V→, SORT, REVLIST, →TAG, DTAG, RANK, TRACE, PEVAL, NDIST, LASTARG, OBJ→, HEAD, TAIL, FFT, IFFT functions, and all stack commands. We will eventually add most (if not all) of those additions.
Also, ND1 tracks all improvements made to the RPL language (CASE, @, DOSUBS, DOLIST, STREAM, SEQ). In v1.3.8, ND1 lacks all “interactive” commands, other than MSGBOX and INPUT. The next update (1.4) will contain most of them.
Compared to the HP-48 family
Various HP-48 family emulators exist on iOS. The previous section applies to them. Further notable differences include:
-Even running on the same hardware, ND1 is about 10x faster in our tests (with large matrices and RPL programs)
-Graphics and fonts on emulators are the same resolution as in the original, so ND1 graphics and fonts are much higher resolved; not to mention that you can zoom, translate, trace graphs, etc. with your fingers
-Emulators don’t support the standard iOS keyboard. Being able to type out a quick command or variable name in ND1 is not only more efficient: once you’re used to this, you feel constrained having to switch to alpha mode and hunt for keys; we feel it makes a huge difference in everyday use
-Emulators are different from most other apps in that they need to explicitly throttle themselves when the calculator is idle. Most impact your battery life, and some drain your battery very quickly. ND1 has no such issues
Emulators do a great job of giving you the original HP-48 experience with improved performance. (At the acceptable expense of a slightly crammed key pad.) ND1 begins with an HP experience but modernizes it in many ways (starting with one tap on the backspace key to undo, double-tapping your stack to see it full-screen, or typing email to email your stack), and adds many of its own unique features.
So, while feature sets may seem similar on paper at first (both work with rich types: vectors, matrices, complex numbers, etc.), the experience, and usability you can get out of both, is quite different. You could use an HP-48 emulator alongside ND1 for its CAS, but there’re much better options available for a CAS on iOS.
Compared to HP-48 emulators on iOS
The HP-49 and hp 50g added substantial CAS system improvements, symbolic vectors and matrices, parallel processing of lists, some notable RPL improvements, Arbitrary Precision Integer (BigInt) support, 3-D graphics, and more to the line.
ND1 supports symbolic vectors and matrices, BigInts, and parallel processing that goes beyond of what the 50g supports: thanks to the unification of lists and vectors, you can do to vectors what you could only to do lists on a 50g.
ND1 does not yet support 3-D graphics, but will do so.
Specific commands of this series supported in MorphEngine v1.3 include: DUPDUP, UNROT, NIP, PICK3, UNPICK, SREPL, GAMMA, GCD, LCM, ISPRIME?, FACTOR, FACTORS, DIVIS, MODSTO, POWMOD, NEXTPRIME, PREVPRIME.
You have all stack operations, and all list processing functions (DOSUBS, DOLIST, STREAM, MAP, SEQ).
In addition to this, again, are unique MorphEngine commands. Some of them are math commands like loggamma, StudentTPDF, quantiles. Others are commands that we saw (from perusing comp.sys.hp48 archives) people wanted in their HP-50g and had to implement themselves. These include functions like insert, removeDuplicates, remove, randomize, permutate (not in CAPS, these are “modern” names) for arrays. You can make use of these commands in RPL, just like classic commands.
We’re transparently extending the RPL language itself, to make it easier to use and faster. See RPL+.
Compared to HP-49 / hp 50g
ND1 will be very recognizable to you as a HP user. As you see, though, ND1 does not aim to re-create a particular model. We embrace the HP calculator model because we really like it, but our gaze is directed toward the future.
HP-28S users should be really happy with ND1, as they only stand to benefit.
HP-48 users may find the overall experience a bit “uneven” (no CAS, HP-28 menu orientation, missing commands, equation library, other nicenesses). On the other hand, you’re picking up many 50g features.
HP-50g users will hopefully appreciate that they’re getting a good chunk of their “king of calculators” (so far) in a pocketable package, and will hopefully like the greater speed, bigger and more interactive stack, and the other unique ND1 features.
We ask you for patience as more of your old calculator is being re-created and becomes available through updates. In v1.3.10, ND1 is at ~430 functions vs. hp 50g’s ~680.
If you programm(ed) your HP, we urge you to see what JavaScript and an HTML5 canvas can do for you.
Read Custom Data Types. This is perhaps the most exciting new feature for programmers.
Conclusion
ND1’s RPL byte-code compiler is faster than an HP-49 emulator running on the same hardware, and substantially faster than an HP-50g.
Here’re some benchmark results to give you a feel for how fast RPL (and RPL+) is in ND1, and how this compares to JavaScript. You can get these programs by downloading the Challenges and RPL+ shared folders.
Below, you’ll find speed relative to HP-50g in parentheses after the ND1 result. The device is an iPhone 3GS.
HHDC 2010 competition (even-odd number sort)
Contest winning entry:
\<< I\->R SORT DUP SIZE 3. ROT +
\<< DUP R\->I SWAP 2. MOD { OVER ROLLD } { UNROT 1. + } IFTE
\>> STREAM DROP \->LIST
\>>
Fed with a vector of 1,000 random integers.
HP-50g: 40.25s [bytes*time score (smaller is better): ~4,000]
ND1: 1.0s [bytes*time score: 83] (41x)
Our “would-be” natural math entry (one of two MorphEngine JavaScript options):
f(v) = v.sort(function(a, b) { return (a%2 && !(b%2)) ? -1 : (!(a%2) && b%2 ? 1 : a-b); })
ND1: 0.034 [bytes*time score: ~2.4] (~1200x)
This compares favorably with an implementation in C (using HPGCC), running on the 50g.
HP-50g (in C): 0.3s [bytes*time score: ~4,900] (134x)
Note, ND1 on an iPhone is still ~10x faster than a HP-50g programmed in C.
Contest winning entry:
\<< DUP HEAD 1 \->LIST SWAP TAIL SWAP 1 3 PICK SIZE
FOR j OVER j DUP SUB ADD 1
\<< DUP DUP + 1 ROT SIZE DUP 4 ROLLD
START DUP 1 4 PICK SUB 3 ROLLD 2 OVER SIZE SUB
NEXT DROP2
\>> DOSUBS
NEXT SWAP DROP
\>>
Fed with string “ABCDEF”, run-times are:
HP-50g: 25.4s
ND1: 1.1s (22x)
MorphEngine has a permutate command that can be applied to a string or a vector.
Run-time for \<< “ABCDEF” permutate \>>
ND1: 0.03s (850x)
This computation produces a 29,993-digit Big Integer result.
HP-50g: 2389s
ND1: 32.5s (~74x)
A popular benchmark test.
≪ RAD
1 1 2499 START
sqrt SQ LN EXP ATAN TAN 1 +
NEXT
≫
HP-50g: 64.3s
ND1: 1.2s (~54x)
This was ported to C (HPGCC), yielding
HP-50g (in C): 2.7s (24x)
and over-clocked (sys_slowOff(), sys_slowOff())
HP-50g (in C; over-clocked): 0.5s (~128x)
The equivalent JavaScript:
function () {
var r = 1;
for (var i=0; i<2499; i++)
r = tan(atan(exp(ln(squared(sqrt(r)))))) + 1;
return r;
}
ND1: 0.12s (~536x)
Fastest RPL entry:
\<< {} 0 \-> results len \<<
27
1000 9999 FOR x
IF x 10 MOD THEN
1 +
ELSE
IF x 100 MOD THEN 8 -
ELSE IF x 1000 MOD THEN 17 -
ELSE 26 -
END
END
END
DUP x SWAP
IF MOD THEN
0 'len' STO
ELSE
IF len 3 == THEN
'results' x len - STO+
ELSE
'len' 1 STO+
END
END
NEXT
results
\>> \>>
HP-50g: 105.3s
ND1: 6.9s (15x)
ND1: 5.6s (19x) [RPL+ version, using ++, 0 =len, ++len instead of 1 +, 0 ‘len’ STO, ‘len’ 1 STO+]
The equivalent JavaScript implementation:
function () {
var results = [], len = 0;
var digitSum = 27;
for (var x=1000; x<9999; x++) {
if (x % 10)
digitSum += 1;
else {
if (x % 100) digitSum -= 8;
else if (x % 1000) digitSum -= 17;
else if (x % 10000) digitSum -= 26;
}
if (x % digitSum)
len = 0;
else {
if (len == 3)
results.push(x-len);
else
len += 1;
}
}
return results;
}
ND1: 11ms (~10,000x)
This is: 1000x faster than the RPL program, 2500x faster than a HP-48 emulator on iPhone, ~200x faster than an Emu48-emulated 49G on a Mac (which, of course is much faster hardware than an iPhone).
« @ Place des deux premier nbr de Fibo sur la pile
{ #1h,#0h,#0h,#0h,#0h,#0h } DUP @ Entiers 64 bits poids faibles -> poids forts
1. 474. START @ calcul les 474 + 2 premiers nombres de Fibonacci
DUP2 @ Duplique les 2 listes
ADD @ Somme des 2 listes élément par élément
1. 5. FOR i @ Gestion des retenues
DUP i GET DUP
#F000000000000000h AND @ Récup le premier bit du quartet le plus 'faible'
IF #1000000000000000h SAME THEN @ et vérifie si il est 'levé' => retenue
#0FFFFFFFFFFFFFFFh AND @ Effacer la retenue
i SWAP PUTI
DUP2 GET #1d + PUT @ Ajouter 1 dans l'entier de poids fort
ELSE
DROP
END
NEXT
NEXT
""
1. 476. START
1. SWAP
UNROT GETI ->H 11. 25. SUB @ Générer le code hexa pour les 6 éléments
UNROT GETI ->H 11. 25. SUB
UNROT GETI ->H 11. 25. SUB
UNROT GETI ->H 11. 25. SUB
UNROT GETI ->H 11. 25. SUB
UNROT GETI ->H 11. 25. SUB
UNROT DROP2
+ + + + + +
NEXT
"GROB 360 476 " SWAP + OBJ-> @ On construit l'objet grahique
»
HP-50g: 170s
ND1 cannot run this code as it contains a non-User RPL instruction: →H
Instead it can run this RPL+ code, which is simpler (and easier to develop):
≪ → n ≪
"FibTriangle"
‘ceil(n*0.7/8)*2’ EVAL * =width
"" =s
1 1 →big toHex
1 n START
DUP ROT +
DUP @toString 3 0 sub width "0" pad
s @swap + =s
NEXT
DROP2
"0x" @swap + width 4 * n image
≫≫
ND1: 0.84s (~200x)
Note, this code uses “modern” RPL syntax, which is meant to be easier to type and read.
You could make the following substitutions and the program would run the same:
“→big” : “R→I” “@toString” : “→STR” “size” : “SIZE” “sub” : “SUB” “@swap” : “SWAP”
The equivalent JavaScript for this task:
function(n) {
var width = ceil(n*0.7/8)*2;
var data = "0x";
var padChar = string.toString("0");
var a = BigInteger.ZERO; var one = BigInteger.ONE; var b = one;
for (var i=0; i<n; i++) {
var val = BigNum["+"](a, b);
a = b; b = val;
// convert number to hex, string, slice off 0x, pad w/ zeroes, and concatenate with data string
data += string.pad(string.toString(BigNum.toString(BigNum.toHex(val)).slice(2)),
width, padChar).slice(1, -1);
}
return NDImage.toImage(string.toString("FibTri" + n), string.toString(data), width*4, n);
}
ND1: 0.7s (~240x)
≪ #67_data OBJ→
2 SWAP START
2 ≪ MAX ≫ DOSUBS
ADD
NEXT
V→
≫
50g: 71.6s
ND1: 0.9s (~80x)
Number of Partitions of an Integer
Computing the number of partitions of the integer 200.
≪ → n ≪
0. 'n>180' {R→I} IFT → zero ≪
0. → k ≪
n mkpents → pents ≪
[0. 1. 1. 0.] → signs ≪
{1.} → partitions ≪
1. n FOR j
zero @ running sum
1. 'k' STO
WHILE
j pents k GET -
DUP @ for re-use next
0. >=
REPEAT
partitions SWAP 1. + GET
signs k 4. MOD 1. + GET {+} {-} IFTE
'k' 1. STO+
END
DROP
'partitions' SWAP STO+ @ add to partitions
NEXT
partitions n 1. + GET
≫≫≫≫≫≫≫
HP-50g: 110.3s
ND1: 11.4s (10x)
ND1: 4.2s (26x) [with ‘n>295’, which works on ND1, thanks to higher precision of Reals]
RPL+:
≪ =n
0 'n>295' {R→I} IFT =zero
n mkpents =pents
[0 1 1 0] =signs
{1} =partitions
0[] @ default to zero-based indexing
1 n FOR j
zero @ running sum
1 =k
WHILE
j pents[k] - =:diff
0 >=
REPEAT
partitions[diff]
signs[MOD(k,4)] {+} {-} IFTE
++k
END
=partitions[j] @ add to partitions
NEXT
partitions[n]
≫
ND1: 1.7s (65x)
ND1 can run also run the equivalent JavaScript implementation:
ND1: 0.26s (~420x)
≪
DUP SIZE
-> s
≪
1 s START
DUP NUM SWAP TAIL
NEXT
DROP s ->LIST
≫
≫
HP-50g: 2.8s
ND1: 0.28s (10x)
This was ported to SysRPL, yielding
HP-50g (SysRPL): 0.7s (4x)
and to C (HPGCC), yielding
HP-50g (in C): 0.13s (21x)
ND1 cannot run the SysRPL or C versions, but it can run the following versions:
RPL+:
≪ =s
{} =list
1 s SIZE FOR i
s[i] NUM =list[i]
NEXT
list
≫
ND1: 0.14s (20x)
(2x faster; note the improved readability)
MorphEngine-specific RPL:
≪ split ≪ NUM ≫ MAP ≫
ND1: 0.13s (21x)
MorphEngine-specific RPL+ (using automatic array processing):
≪ split NUM ≫ or (using modern syntax) ≪ split charCode ≫
ND1: 0.08s (35x)
Mixed GolfScript/RPL+:
≪ =:s str2stack s SIZE ->LIST ≫ (w/ str2stack: gs:{}*)
ND1: 0.04s (70x)
JavaScript:
function(x) { return calculator.unquote(x).split("").map(function(x) { return x.charCodeAt(0); }); }
ND1: 0.004s (700x)
We have plans for next steps, employing code-morphing, for further substantial speed gains in RPL. See this note.
Appendix: Benchmarks