What are current options for plain arithmetic?

I was concerned about that, so I did a little bit of testing trying to eval javascript code.

TiddlyWiki gave a nasty “this is embarrassing” error every time, so I gathered TiddlyWiki is doing something to prevent eval from running the javascript code. So something about the TiddlyWiki design that is keeping things safe?

Is TiddlyWiki not doing something to prevent the security risk we are thinking about?

Oops, I must have made an error in my testing.

Easy peasy fix to the eval function so that it only accepts numerics and arithmetic characters.

Give me an hour or two.

Is something like

{{{ [{!!a}multiply{!!b}] +[divide[2]] }}}

Not plain enough?

Yes when just dealing with just several numbers and operands.

I’m thinking more complicated arithmetic, like 1 + 2 * (3 + (4 * 5 + 6 * 7 * 8) - 9) / 10

So the macro reference looks like this:

<<EvalThis "1 + 2 * (3 + (4 * 5 + 6 * 7 * 8) - 9) / 10">>

Sure

But even your example can be broken into seperate pieces then combining them at the end. In many cases there may be value in this logical arrangement effectivly allowing you to name intermediate results. Further the values can be litteral, field or text reference, a variable or the output of a previous filter step.

I understand where you are comming from however sometimes limitations are the mother of invention. In someways breaking the problem into named pieces helps clarity, readability and ourselves when we return after an absence to relearn what we were thinking before.

I will present an example tomorrow.

Yes, I know how to do it the TiddlyWiki way.

I could have done that, but I really wasn’t interested.

Great for you to put that kind of sample together to include in this thread, though.

Update: EvalThis for Simple Arithmetic — a non-linear personal web notebook

Locked down the related javascript macro to only allow the following characters to be processed, returning an error if anything else is is the expression:

  • 0123456789 ()±*/%

Anything other than those specific characters, and you get the following result:

:exclamation:invalid expression​:exclamation:

1 Like

good stuff but you need to capture errors such as

<<EvalThis “0()”>>

1 Like

Ugh. No wonder I hate javascript. I’ll play around with that.

That was close to tears painful.

Although I appreciate something silly all of the good stuff folk have done with javascript, do javascript and I ever not get along.

Regardless, thanks @buggyj !!!

Nothing fancy, but much more resilient, I think.

Whatever gets passed to the TiddlyWiki macro gets wikified before getting passed to javascript for arithmetic evaluation.

The final result of Wikification must result in a valid arithmetic expression that has nothing but the following characters (excluding double-quotes): "0123456789 ()+-*/%" (yeah, there is a space in there)

<<EvalThis "0()">> will give ❗invalid arithmetic expression❗

For those interested, the javascript behind it all:

function(expr) {
try {
    var expr_check = expr;
    for (var i = 0; i < expr.length; i++) {
        if ( '0123456789 ()+-*/%'.indexOf(expr[i]) == -1) {
            expr_check = 'crap';
            break;
        }
    }
    var sReturn = eval(expr_check);
    if ( sReturn == '' ) {
        sReturn = '0'
    }
 return sReturn;
}
catch {
 return '❗invalid arithmetic expression❗';
}
1 Like

@Charlie_Veniot - to import your creation, is all that is needed these two tiddlers, i.e the macro and the js tiddler? Very lightweight in that case - nice! Do you plan on making a plugin from it?

Yup, just those two.

Although nobody would guess from my verbose self, I do love minimalism when it comes to “solutions”.

Two wee plugins and a no-nonsense way of expressing lengthy arithmetic expressions (well, when only basic arithmetic is needed), that’s my cup o’ tea for sure.

If one needs more, my first vote is to blend with the already existing math functionality in the filter operators. If more is needed, goto them plugins.

Not a fan of the process involved in creating plugins. Maybe I’ll just setup a “package” for easy single-file drag’n drop.

I kind of like the idea of folk being able to rename/organize those two tiddlers however they like, or even just nab the code (well, that one TW macro, maybe best to leave the javascript one alone) to put into tiddlers they have already. A “weave into your stuff as per your preferences” philosophy?

Actual I withdraw this offer on your example 1 + 2 * (3 + (4 * 5 + 6 * 7 * 8) - 9) / 10 because it is itself mathematically unnecessarily complex. for example the innermost parentheses need not be 3+ then -9 (only -6). Clearly you got the monkeys at a typewriter #1, to generate a random calculation :nerd_face:

Here is the simple interest formula as an example of my argument, which is not deigning your need, simply demonstrating a valid alternative, to addressing the thread “What are current options for plain arithmetic?”.

Place this in a tiddler on tiddlywiki.com
Here is the simple interest formula as an example.

<$let 
principal=5000 
interest="0.02"
years="10" 
percent-interest={{{ [<interest>multiply[100]] }}}
dollar={{{ [<interest>multiply<years>add[1]] }}}
total-interest={{{ [<dollar>multiply<principal>] }}}
total-repayments={{{ [<principal>add<total-interest>] }}}
months={{{ [<years>multiply[12]] }}}
monthly-repayment={{{ [<total-repayments>divide<months>] }}}
>

;R = P (1 + rt)
* Principal (P) $<<principal>> 
* Interest rate (r) <<percent-interest>>% over <<years>> years (t) 
* Total interest= $<<total-interest>>, thus Principal + Interest = <<total-repayments>>
* Monthly repayments = $<$text text={{{ [<monthly-repayment>round[2]] }}}/> over <<months>> months.

</$let>

This approach has a number of advantages;

  • Plain english variables
  • All intermediate values available
  • Easy and readable opportunities to display the results in many ways.
  • Can replace the “input values” with tiddler, field or variable references
  • Easy to manually edit input values.
  • Easy to reuse / can transclude if using current tiddler fields as input
  • Can move the input values outside of the formulae.

#1 I also enjoy The Infinite Monkey cage

I picked an example related to recent work parsing arithmetic equations, which is what had me thinking about how best to handle complex arithmetic in TiddlyWiki.

From https://rosettacode.org/wiki/Arithmetic_evaluation#BBC_BASIC:

Input = 1 + 2 * (3 + (4 * 5 + 6 * 7 * 8) - 9) / 10
AST =   ((1)+(2*((3)+(((4*5)+(6*7*8)))-(9))/10))
Value = 71

Related for your amusement:

I’ve seen complex enough arithmetic equations in my day to see value in a simple EvalThis arithmetic expression macro.

I just couldn’t think of any off the top of my head.

How about the distance formula to find the distance between two points in a plane?

Screenshot 2022-03-12 9.25.01 PM

Do you want us to try that one?

2 Likes

I challenge thee!

Here’s my version for the problem further below:

<<EvalThis "( ( 2 - (-3) )**2 + ( 3 - (-1) )**2 )**(1/2)">>

I think we are missing the square root maths operator.

But here is an untested example of the above; with a fictional sqr-root macro

<$let X1=4 X2=6 Y1=2 Y2=10
delta-x={{{ [<X2>subtract<X1>] }}}
delta-y={{{ [<Y2>subtract<Y1>] }}}
delta-x-squared={{{ [<delta-x>power[2]] }}}
delta-y-squared={{{ [<delta-y>power[2]] }}}
square-of-d={{{ [<delta-x-squared>add<delta-y-squared>] }}}
>

*square-of-d=<<square-of-d>>
*Distance=`<$macrocall $name=sqr-root input=<<square-of-d>>/>`
</$let>

PS I am not at all a mathematician so prone to error.

[Edit]

  • Using the filter or subfilter operators could help combining more than one “computation” into one.
  • Creating macros could also help
    • Perhaps where we pass a variable name rather than a value.
\define square(varname) {{{ [[$varname$]getvariable[]power[2]] }}}
<$let input=2>
example=<<square input>>
</$let>

Although it is an Interesting challenge.

  • In my approach there could be some useful supporting macros.
  • Thanks for reminding me about Square Root is just to the power of 0.5

So lets update the above

  • One less macro, one additional $let
  • Prefix our variables in use “P-”, so we can autolist them and their values.
  • Notice how we only display the result to a fixed number of places, the variable distance retains its precision.
<$let P-X1=4 P-X2=6 P-Y1=2 P-Y2=10
delta-x={{{ [<P-X2>subtract<P-X1>] }}}
delta-y={{{ [<P-Y2>subtract<P-Y1>] }}}
delta-x-squared={{{ [<delta-x>power[2]] }}}
delta-y-squared={{{ [<delta-y>power[2]] }}}
square-of-d={{{ [<delta-x-squared>add<delta-y-squared>] }}}
distance={{{ [<square-of-d>power[0.5]] }}}
>
<$list filter="[variables[]prefix[P-]]">
   <<currentTiddler>> = {{{ [<currentTiddler>getvariable[]] }}}<br>
</$list>
Distance = {{{ [<distance>fixed[3]] }}}
</$let>

As the example above shows with the prefix[P-]] where our variables are named with a prefix we can make use of later (suffix also simultaneously possible) demonstrates how easy it is to then leverage TiddlyWiki’s title and string handling in filters to open a whole new way of doing maths, or logic by manipulating numbers based on names. We could even lookup a tiddler/field based on a title/variable name.

  • This is all before passing parameters to macros that read like variables

Square Root is just to the power of 0.5 (aka 1/2). I wouldn’t bother going through the trouble of setting up something for square root.

If that gives the same final number as mine, then it is A-1.

Absolutely nothing wrong with what you have there. Quite nice, just way too much overhead for this kid.

In a TiddlyWiki involving a lot of equations, something meant for scientists/mathematicians/engineers, I’d much prefer stick to the short and sweet.

The ability to take a formula and apply it as is, I can’t pass that up.

But if I were a student working on a thesis or book report, I might want to break it down like you just did as part of explaining the equation. Maybe. More likely I’d stick to Distance in the Coordinate Plane | College Algebra.

Definetly something which looks more maths like works for me!

I had a spell as a cobol programer and we had auditors and business analysts that may wish to review the calculations in the code which influenced the above approach. This also is a form of self documentation and easier to maintain. By spelling out and naming intermediate results the formulae is more adaptable and the output can present the input or meaninful intermediate results.

As I hinted at there may be some innovative posibilities we are yet to explore since tiddlywiki has powerful title manipulation and the titles. Can be variable names and a matching tiddler for each variable could carry more information such as display format, relavant units, tooltips and much more.

Please understand you do what suits you. What I am trying to do is promote innovative extencible alternatives.

BASIC. My favourite right after Gupta Team Developer (aka Gupta SQLWindows.)
COBOL. Excellent for what it was made for.
Modula II. That was good stuff.
Pascal was pretty good, but annoyed me for some reason.
FORTRAN was pretty good.

Not a particular fan of any other programming languages. Hated APL, yet love TiddlyWiki filtering.

SQL is the bomb.

Sure, there are times in which heavy code is needed, but I should have been more clear about my interest here, which is all about minimalism: complex arithmetic that can be coded simply and plainly and that looks like the actual equations.

A discussion of minimalism vs voluminous and everything in between, and when any one or the other or a middlin’ one make the most sense, that’s worth of a full thread, maybe many threads.

I got what I needed out of this discussion. i.e. there was nothing out there that offered what I wanted, so I built it. And it does exactly what I want, and nothing more.

<<EvalThis "( (x2-x1)**2+(y2-y1)**2 )**(1/2)">>

That’s perfect for the things I have in mind. But just for the things I have in mind, which match formulas from text books.

The exact same mechanism with well-worded tiddler/field titles still looks good when the arithmetic isn’t too complex:

total cost = <<EvalThis "{{ item_price }} * ( 1 + ( {{( [[tax_rate]removesuffix[%]] })} / 100 ) )">>

Rock’n roll !

1 Like