You are not logged in.

- Topics: Active | Unanswered

**y27****Member**- Registered: 2009-05-27
- Posts: 147
- Website

Updated to version 0.9.2, I added gmul(), a 2D graphing function, but for multiple functions on the same graph, so for example

`gmul(x,x^2,x^3,x^4)`

would produce something like:

I also fixed a bug with discontinuities, the cause was quite stupid; because I was checking for discontinuities by looking when hc_result_ (the "core" computing function) returned an error, but since I now implemented complex numbers, it won't return an error when it should from the point of view of the grapher. Everything should work correctly now, but if you find any bugs etc. don't hesitate to contact me.

Offline

**raymboard****Member**- Registered: 2010-01-22
- Posts: 61

I can't compile plplot.

*Last edited by raymboard (2010-01-27 20:45:20)*

Linux is not an operating system it's a kernel. You're using GNU/Linux. http://www.gnu.org/gnu/linux-and-gnu.html

Offline

**y27****Member**- Registered: 2009-05-27
- Posts: 147
- Website

raymboard wrote:

I can't compile plplot.

Which version of cmake do you have? Have you tried with 2.6?

By the way, the package maintainer of plplot (imrehg) on AUR says here http://aur.archlinux.org/packages.php?ID=1089 that it's fixed in the plplot svn, so you could also try replacing plplot with plplot-svn if downgrading cmake does not work.

Offline

**y27****Member**- Registered: 2009-05-27
- Posts: 147
- Website

So, have you managed to build it?

By the way, I released 0.9.3, adding basic implied multiplication so you don't have to spell everything out anymore

Offline

**y27****Member**- Registered: 2009-05-27
- Posts: 147
- Website

OK, another update - 0.9.4:

- added \load - a direction that allows you to read in a text files with

HC commands, definitions, etc. Can be used for example for storing

functions that you use often, etc.

- added rand() and round()

- rewrite of a part of the hc_result_() function; should now be faster for

the most common case, and also provides "better" (==more informative)

error messages to the user

- small bugfix for user functions/vars with names including numbers

As usual having some testers would be great.

EDIT: I now have made the git repo public at http://github.com/houbysoft/hc , look there for the newest version

*Last edited by y27 (2010-03-03 22:40:05)*

Offline

**y27****Member**- Registered: 2009-05-27
- Posts: 147
- Website

Updated to 1.0; this time I added logic operators and a very simple programming language kind of similar to C, more details about those are here.

**new**:

Updated to 1.1;

- added basic string support and the function mmass() which expects

a string as its first argument, a valid molecule, and returns its

molar mass

- added input(), a function to request user input mainly in programs

- added write(), a function that behaves like print(), but writes to a file,

which needs to be specified as its first argument

- print() and write() can now also print strings

- added possibility to pass a filename to hc (CLI only) which will then

be executed

- some fixes and optimizations

*Last edited by y27 (2010-04-01 22:15:20)*

Offline

**y27****Member**- Registered: 2009-05-27
- Posts: 147
- Website

Updated to 2.0:

- added vectors; they can be used with normal operators

where appropriate, and can also be used with functions crossP() and dotP().

example usage : crossp([1,2,3],[4,5,6])

- added graphpeq() to draw parametric equations

- added slpfld() to draw slope fields

- a few bugfixes and optimizations

AUR packages have been updated.**Edit: Switched dependency plplot to plplot-svn because the plplot package in AUR is broken.**

Any feedback is appreciated as usual.

*Last edited by y27 (2010-05-23 05:30:45)*

Offline

**y27****Member**- Registered: 2009-05-27
- Posts: 147
- Website

Version 3.0 was released, so I'm keeping this thread up-to-date.

Release notes are below.

```
- completely new help system with the help() function
- completely new control structure system -- control structures
are now functions. Why? No new syntax to learn for newbies,
easier (therefore faster) parsing, consistent syntax.
- added -e command line argument for direct evaluation from cli arguments
- numbers can now be also entered in hex (with the 0x prefix)
and in binary (with the 0b prefix)
- added a few synonyms : quit for exit, and arc* for asin, acos, atan
- added join() to join lists/vectors
- added re()/real() and im()/imag() to get only
real / imaginary part of a number
- logic operators precedence bugfix, and added ! as the logical NOT operator
- added codetochar() and chartocode() to work with character
codes and made strings indexable
- added length() to get length of lists/vectors and strings
- many bugfixes, optimizations, etc.
```

Offline

**livibetter****Member**- From: Taipei
- Registered: 2008-05-14
- Posts: 95
- Website

Firstly, I love this calculator!

Heart Curve by livibetter, on Flickr

```
r(t)=2-2sin(t)+sin(t)*sqrt(abs(cos(t)))/(sin(t)+1.4)
graphpeq(r(t)*cos(t),r(t)*sin(t),0,2pi,-3,3,-4,1)
```

Few hours of trying this and that, I had learned some basics...

**Arch is the best!**

`print("Arch is the best!")`

**Recursion**

HC stopped me when it found out I was trying to define a recursion function, but...

```
fibr(n)=fib(n)
fib(n)=if(n>=0,
if(n==0,0,
if(n==1,1,
fibr(n-1)+fibr(n-2)
)
)
)
```

I am so bad.

**Then, the FFT!**

```
fft(x)=for(k=0,k<length(x),k+=1,
xk=0;
for(j=0,j<length(x),j+=1,
a=x[j];
b=exp(-2pi*k*j*0i1/length(x));
xk+=a*b;
);
print(xk);
)
```

```
> x = [1,0,3i-3,4i5,5]
> fft(x)
13i2
-7.8203160070896799i3.7250338450183462
6.7264861191111235i2.6059037339171068
-8.4904181416113337i-1.3698357564173172
1.5842480295898901i-6.9611018225181358
```

Result from SciPy:

```
>>> import scipy
>>> scipy.fft([1,0,3-3j,4+5j,5])
array([ 13.00000000+2.j , -7.82031601+3.72503385j,
6.72648612+2.60590373j, -8.49041814-1.36983576j,
1.58424803-6.96110182j])
```

**Some suggestions**

I found some problems, first one is if I re-write the FFT with:

`xk+=x[j]*exp(-2pi*k*j*0i1/length(x));`

I got message about index must be integer, I think this is a bug.

Second one is **vector**, the output of fft() is useless because I can not use it. I tried to use `join()` to put those into vector but...

```
y=[1]
v=join(y,[2])
```

I got error about the both parameters must be vector. HC didn't check type of y.

Also, we should be allowed to substitute any element of a vector, e.g. `v[2]=3`.

(Edit: I forgot to mention, when I was doing graphing. Sometimes, same code would result 'Segmentation fault'. If you try again, HC works fine. I don't have the precise procedure to reproduce it, I will provide more if I can have something concrete. PS. I'm not an Arch user.)

*Last edited by livibetter (2010-08-24 07:26:06)*

Offline

**y27****Member**- Registered: 2009-05-27
- Posts: 147
- Website

Nice curve

For the recursion check, I might actually remove it, in retrospect it's not really serving any purpose, if a user screws up (ie something like myfunc(a) = myfunc(a)), that's too bad, but it should not limit the functionality for "legal" definitions.

By the way, not sure if you knew it, but for the fibonacci sequence, there is also a built-in function : fibo().

I just fixed the join() problem, sorry, it's in the latest git revision now.

I don't have that much time right now but I'll look into the issue with the indexes having to be integers, and I'll implement v[2] = 3 sorts of things probably soon too.

Offline

**livibetter****Member**- From: Taipei
- Registered: 2008-05-14
- Posts: 95
- Website

y27 wrote:

By the way, not sure if you knew it, but for the fibonacci sequence, there is also a built-in function : fibo().

Yes, I do know `fibo()`, I use it to check `fib(10) == fibo(10)`, I just didn't copy and paste the sample code from my blog posting and I used it as example because it's simple to make.

y27 wrote:

I just fixed the join() problem, sorry, it's in the latest git revision now.

Awesome, it now works! But I found another bug:

```
> y = []
> join(y,[1])
[,1]
```

I expect `[1]`, here is a diff:

```
diff --git a/hc_functions.c b/hc_functions.c
index 8ea2492..5e3fc73 100644
--- a/hc_functions.c
+++ b/hc_functions.c
@@ -1780,11 +1780,12 @@ char *hc_join(char *f_expr)
}
char *v1 = list_clean(v1_orig);
char *v2 = list_clean(v2_orig);
+ char *sep = (v1[0]==0||v2[0]==0) ? "" : ",";
- char *r = malloc(strlen(v1)+strlen(v2)+4);
+ char *r = malloc(strlen(v1)+strlen(sep)+strlen(v2)+3);
if (!r)
mem_error();
- sprintf(r,"[%s,%s]",v1,v2);
+ sprintf(r,"[%s%s%s]",v1,sep,v2);
free(v1_orig); free(v2_orig);
return r;
```

There seems to have problem with Makefile (I forgot to mention in my last reply):

```
gcc `pkg-config --cflags --libs plplotd` main.o hc.o hc_functions.o hc_varassign.o hc_graph.o hc_complex.o m_apmc.o hc_stats.o hc_programming.o hc_chemistry.o hc_list.o hc_help.o hc_utils.o /usr/lib/libmapm.a -lgd -lm -lreadline -o hc
gcc: /usr/lib/libmapm.a: No such file or directory
make: *** [hc] Error 1
```

I have to change 'libmapm.a' to 'libmapm.so.0' in the Makefile. I don't know if this is because of distro difference. Last time, I was compiling using commands from PKGBUILD, which uses '.so.0'.

```
diff --git a/Makefile b/Makefile
index 229ce08..0719222 100644
--- a/Makefile
+++ b/Makefile
@@ -14,7 +14,7 @@ LOPT=
OBJS=main.o hc.o hc_functions.o hc_varassign.o hc_graph.o hc_complex.o m_apmc.o hc_stats.o hc_programming.o hc_chemist
ry.o hc_list.o hc_help.o hc_utils.o
hc: cleanup ${OBJS}
- gcc `pkg-config --cflags --libs plplotd` ${LOPT} ${OBJS} /usr/lib/libmapm.a -lgd -lm -lreadline -o $@
+ gcc `pkg-config --cflags --libs plplotd` ${LOPT} ${OBJS} /usr/lib/libmapm.so.0 -lgd -lm -lreadline -o $@
cleanup: hc.make.cli
```

Offline

**y27****Member**- Registered: 2009-05-27
- Posts: 147
- Website

Thanks for the patches, both have been applied + I also changed the libmapm.a to libmapm.so.0 in `Makefile.gui`. I have both the static and dynamic versions on my system but most distros (including the mapm PKGBUILD for Arch) now install the dynamic version, so using it will indeed be better.

In the PKGBUILD, it's always been libmapm.so.0 so that it works properly when the Archlinux mapm package is installed as a dependency.

Offline

**y27****Member**- Registered: 2009-05-27
- Posts: 147
- Website

I also just changed the error for recursive definitions to just be a warning now, so you can implement your own fibonacci number function using the recursive definition (which is of course very slow compared to the algorithm fibo() uses, but yes it's a nice example ) by something like:

`fib(n) = if(n<2,n,fib(n-1)+fib(n-2))`

instead of tricking HC

Offline

**livibetter****Member**- From: Taipei
- Registered: 2008-05-14
- Posts: 95
- Website

y27 wrote:

I also just changed the error for recursive definitions to just be a warning now, so you can implement your own fibonacci number function using the recursive definition (which is of course very slow compared to the algorithm fibo() uses, but yes it's a nice example ) by something like:

`fib(n) = if(n<2,n,fib(n-1)+fib(n-2))`

instead of tricking HC

Great! Because I don't like cheating!

And this is a modified version of FFT after join() is fixed:

```
fft(x)=for(k=0,k<length(x),k+=1,
for(j=0,j<length(x),j+=1,
a=x[j];
b=exp(-2pi*k*j*0i1/length(x));
xk=if(j==0,a*b,xk+a*b);
);
y=if(k==0,[xk],join(y,[xk]));
)
```

Result:

```
> x = [1,0,3i-3,4i5,5]
> fft(x)
> y
[13i2,-7.82031600708967988155423447147825i3.72503384501834614154631578717033,6.72648611911112342513610150140065i2.60590373391710692193167727418164,-8.4904181416113337287269278326694i-1.36983575641731722552250360545038,1.58424802958989018514506080274697i-6.96110182251813583795548945590165]
```

Offline

**y27****Member**- Registered: 2009-05-27
- Posts: 147
- Website

Nice

By the way, there also is an easier way to pass the result; in HC, the return value is the first command that actually returns something.

For example:

`x=2; 3; y=4;`

would return 3, and stop execution there (y would not be set), because it first executes x=2, which does not return a value, and then it executes 3, which does return a value -- a number, 3.

You can use this mechanism to modify fft() a little:

```
fft(x)=for(k=0,k<length(x),k+=1,
for(j=0,j<length(x),j+=1,
a=x[j];
b=exp(-2pi*k*j*0i1/length(x));
xk=if(j==0,a*b,xk+a*b);
);
y=if(k==0,[xk],join(y,[xk]));
if(k==length(x)-1,y);
)
```

Then you can simply run:

```
> fft([1,0,3i-3,4i5,5])
[13i2,-7.8203160070896799i3.7250338450183461,6.7264861191111234i2.6059037339171069,-8.4904181416113337i-1.3698357564173172,1.5842480295898902i-6.9611018225181358]
```

and as you see you'll get the result directly.

I also plan to make it possible, in a future version, to include some function, let's say module(), that will allow something like this:

```
fft(x)=module(
for(k=0,k<length(x),k+=1,
for(j=0,j<length(x),j+=1,
a=x[j];
b=exp(-2pi*k*j*0i1/length(x));
xk=if(j==0,a*b,xk+a*b);
);
y=if(k==0,[xk],join(y,[xk]));
);
y
)
```

to work.

*Last edited by y27 (2010-08-25 08:04:34)*

Offline

**y27****Member**- Registered: 2009-05-27
- Posts: 147
- Website

Just fixed the bug with the message saying that index must be an integer, even when it is.

Therefore, it is now possible to implement the FFT as:

```
fft(x)=for(k=0,k<length(x),k+=1,
xk = 0;
for(j=0,j<length(x),j+=1,
xk+=x[j] * exp(-2pi*k*j*0i1/length(x));
);
y=if(k==0,[xk],join(y,[xk]));
if(k==length(x)-1,y);
)
```

Offline

**livibetter****Member**- From: Taipei
- Registered: 2008-05-14
- Posts: 95
- Website

y27 wrote:

Just fixed the bug with the message saying that index must be an integer, even when it is.

Therefore, it is now possible to implement the FFT as:

`fft(x)=for(k=0,k<length(x),k+=1, xk = 0; for(j=0,j<length(x),j+=1, xk+=x[j] * exp(-2pi*k*j*0i1/length(x)); ); y=if(k==0,[xk],join(y,[xk])); if(k==length(x)-1,y); )`

Thanks for fixing it.

I noticed a performance problem with `length()`. (it's because of the design, may not see it as an issue).

```
> time hc ~/test.hc
real 0m0.210s
user 0m0.188s
sys 0m0.006s
> time hc ~/test1.hc
real 0m0.112s
user 0m0.107s
sys 0m0.003s
```

test1.hc is almost twice faster than test.hc.

The first one (test.hc) is from the code in quote above. The second one (test1.hc) is:

```
fft(x)=for(k=0,k<length(x),k+=1,
xk = 0;
N = length(x);
for(j=0,j<N,j+=1,
xk+=x[j] * exp(-2pi*k*j*0i1/N);
);
y=if(k==0,[xk],join(y,[xk]));
if(k==N-1,y);
)
```

I assigned the result of `length(x)` to `N`. I read the source code, HC basically parses everything every time. It's the design, so I guess some HC coding trick is necessary for speed.

(edit: `x = [1,2,3,4,5,6,7,8,9,10]`)

(edit: this is slightly faster:

```
fft(x)=for(k=0;N=length(x);y=[],k<N,k+=1,
for(j=0;dd=-2pi*k*0i1/N;xk=0,j<N,j+=1,
xk+=x[j] * exp(dd*j);
);
y=join(y,[xk]);
if(k==N-1,y);
)
```

PS: I think I should say "parse and evaluate" expression/variable, instead)

*Last edited by livibetter (2010-08-25 21:45:09)*

Offline

**livibetter****Member**- From: Taipei
- Registered: 2008-05-14
- Posts: 95
- Website

I want to have tilde expansion in CLI interface for `\load`, so I can `\load ~/tmp/test.hc`:

```
diff --git a/hc.c b/hc.c
index 186e9d3..7ffeea9 100644
--- a/hc.c
+++ b/hc.c
@@ -2433,6 +2433,13 @@ char hc_is_predef(char *var)
void hc_load(char *fname)
{
+ char *homedir = getenv("HOME");
+ char *new_fname = malloc(sizeof(char)*(strlen(fname)+(homedir?strlen(homedir):1)));
+ if (strstr(fname, "~/") == fname && homedir)
+ fname = strcat(strcpy(new_fname, homedir), fname+1);
+ else
+ fname = strcpy(new_fname, fname);
+
FILE *fr = fopen(fname,"r");
if (!fr)
{
@@ -2473,4 +2480,5 @@ void hc_load(char *fname)
}
fclose(fr);
free(expr);
+ free(fname);
}
```

This probably not a good patch since I am not good at C.

Offline

**y27****Member**- Registered: 2009-05-27
- Posts: 147
- Website

For the speed issue, yes this is "by design", at least for now; mainly for simplicity, since some form of caching would imply more complexity. However, in the future, some optimizations of this kind will probably be implemented. I'll probably work on this sort of thing for the next big release (I also plan to release a minor version rather soon with the changes and fixes you suggested before etc., plus maybe one other small feature request by a friend).

For the `~` expansion, I'll try to include that in the next minor version release as well, however I'll have to change it a little, or at least disable it on Windows, since on Windows, `~` does not have this meaning and I want HC to be as portable as possible.

*Last edited by y27 (2010-08-26 19:28:14)*

Offline

**y27****Member**- Registered: 2009-05-27
- Posts: 147
- Website

I had some time, so I implemented the earlier request:

Also, we should be allowed to substitute any element of a vector, e.g. `v[2]=3`.

This is now possible in the latest git revision, please test

Offline

**y27****Member**- Registered: 2009-05-27
- Posts: 147
- Website

Also now implemented tilde expansion, using `wordexp` (man wordexp), which is cleaner/better than the patch, since it also supports other expansions of the `~`; for example:

```
~ becomes user's home
~USERNAME becomes USERNAME's home
etc.
```

On WIN32, this is disabled.

Offline

**livibetter****Member**- From: Taipei
- Registered: 2008-05-14
- Posts: 95
- Website

y27 wrote:

I had some time, so I implemented the earlier request:

Also, we should be allowed to substitute any element of a vector, e.g. `v[2]=3`.

This is now possible in the latest git revision, please test

This is great. But I think we also need initialization functions, such as `zeros()` in MATLAB, though we can user-define one.

`zeros(n) = for(j=0,j<n,j+=1,if(j==0,y=[0],y=join(y,[0]);if(j==n-1,y)))`

And the `~` expansion is great, I have seen that `wordexp` but it requires a header inclusion and it's many feature we don't need, so I thought do it by self might be a better option. But my code is a mess.

Offline

**y27****Member**- Registered: 2009-05-27
- Posts: 147
- Website

@zeros:

Added, with the same functionality as your code

Also added ones(), which does the same as zeros() but puts 1's in the array. This can be useful since it's then possible to generate an array containing any constant numbers (ie to generate a list of 3 42's, one can do ones(3) * 42).

Offline

**Awebb****Member**- Registered: 2010-05-06
- Posts: 4,880

Is there a predefined variable wich buffers the last result? This is usually done by an ANS button on hardware calculators.

Offline

**y27****Member**- Registered: 2009-05-27
- Posts: 147
- Website

Yes, there is ans() (it's currently a function and not a variable so that it is similar to the TI-89 hw calculator).

Offline