mathjs icon indicating copy to clipboard operation
mathjs copied to clipboard

Option to choose default angle units

Open canbax opened this issue 4 years ago • 15 comments

Thanks for this powerful library. I want to use evaluate function to compute math expressions.

Certain operators like sin, cos use default unit radian. For example: evaluate(sin(3.14/2)) gives 1. Can I change the default unit to the degree? e.g. evaluate(sin(90)) will give 1.

I think there should be a config to set the default units used in calculations.

canbax avatar Feb 05 '20 21:02 canbax

You can do evaluate('sin(90 deg)') for example, would that work for you?

josdejong avatar Feb 08 '20 11:02 josdejong

not really. It would be more convenient for me to use directly evaluate('sin(90)'). A configuration for the default units would be nice

canbax avatar Feb 08 '20 15:02 canbax

It may be good indeed to reconsider adding support for config options deg//rad/grad. It's quite common for calculators, which is one of the cases where mathjs is often used.

See also this topic where I explain my hesitation in this regard: https://github.com/josdejong/mathjs/issues/944#issuecomment-331626878

Math.js indeed has no configuration for deg/rad. I'm a bit hesitant to implement such a configuration, since it's so easy to make mistakes. I prefer to use explicit units when possible (like sin(34 deg)), but this may indeed not be feasible in all cases. I would love to hear more about your use case - maybe we can somehow improve mathjs to accommodate for it.

See this example for an idea on how to add support for deg/rad: http://mathjs.org/examples/browser/angle_configuration.html.html

josdejong avatar Feb 10 '20 19:02 josdejong

I couldn't understand why "it's so easy to make mistakes". When a user enters expression like "sin(34)" changing them like "sin(34 deg)" for every trigonometric function is hard because there might be nested trigonometric functions. It is also tiring for the eye.

canbax avatar Feb 11 '20 05:02 canbax

I've made this mistake multiple times in my life doing some calculations with a calculator, and at some point thinking "whuut? there is something weird going on here", only to figure out that I was filling in values in degree whilst the calculator was set to rad or the other way around.

It's a bit similar to implicit multiplication (like 1/2x) which can bite you too.

I do see the value of it though I'm not a fan of these kind of implicit things myself, I'm open to reconsider adding support for rad/deg/grad after all.

josdejong avatar Feb 13 '20 19:02 josdejong

I wish this configuration support was ready. I am Working on a calculator plugin for a CBT system. Over here in Nigeria DEG is the default. I implemented my calculator with a simple evaluate(expression). Works like a charm except I can't set default angles.

I think I need to understand that angles examples first.

tobychidi-zz avatar Mar 15 '22 23:03 tobychidi-zz

@Tobychidi I built a calculator https://github.com/canbax/hasap Here I make a topological sorting of math expressions and then change the angle units one by one https://github.com/canbax/hasap/blob/7d6a28aa1a757e6b536727b5fce2842e00a7f755/src/app/app.component.ts#L513

canbax avatar Mar 17 '22 18:03 canbax

TL;DR: The reason there is no "degree mode" in mathjs is that it is a very large amount of work, and it's not clear how to get everything consistent (or whether it's possible), and so the payoff has not been worth anyone's effort when it's pretty easy either to just write the units, define your own functions 'cosd' and 'sind' that take degrees, or use one of the other workarounds that have been posted in this issue.


My full thoughts:

I wanted to add that adding a configuration setting for "degree" input to trigonometric functions is not as straightforward as it might seem. In a wide-ranging math library, not only do you have to modify the behavior of the six basic trigonometric functions, but also their inverses. And since we have derivative, well, the derivative of the sine function of angles measured in degrees is not cosine, even if you mean cosine of angles in degrees, it's (π/180)*cosine. So you have to be very careful to change the derivative operation as well, for all affected functions. And what about polar coordinates? If angles are measured in degrees, all of the polar coordinate functions have to change their behavior as well. And since the exponential function for complex numbers is closely connected with trigonometric functions (exp(ia) = cos a + i sin a), the exponential function has to change its behavior too (euler's formula becomes e^(180*i) + 1 = 0, for example). And that means that the power and log functions have to change also, so that they are consistent with exp. In fact, the majority of all mathematical operations on complex numbers have to change. I am not actually 100% certain there is a fully consistent set of mathematical operations on real and complex numbers in which one "measures angles in degrees." I think it can be done, but there are many many details that would need tracking down.

So you see, there are very good reasons why mathematics as a whole measures angles in radians, and so why a computer math package that tries to cover a broad range of topics also measures angles in radians. It is very much not just an arbitrary choice.

In fact, I would say that mathjs goes farther than many general math packages in supporting degrees, by allowing expressions like cos(30 deg). Now that unicode is essentially universal, would it help to also support cos(30°) ? That would be quite easy and I would be glad to do it if it would be helpful.

gwhitney avatar Mar 22 '22 00:03 gwhitney

Thanks for your input Glen!

On the one side I would love to make this configurable, on the other hand I want to stay away from it because of the complexities it involves.

One idea could be to find a middle way: support configurable angle units for all the "basic" trigonometric functions (sin, cos, tan, asin, acos, atan, etc). And for other functions like the derivative built a check which just throws an exception when the angle configuration is not rad, saying that it is not supported. It may be tricky to save guard this everywhere though, I'm not sure. What do you think @gwhitney?

The current situation is also not 100% as I would want it, because it is not really symmetric. You can enter cos(30 deg), then the output is a number 0.8660254037844387. But when then calculating acos(0.8660254037844387), the response is a number 0.5235987755982987, which is "just" in rad. I would love to return a unit unit('0.5235987755982987 rad'), so there cannot be a mistake in that and you can directly convert it to say deg if you want. Such a feature should probably be behind a feature toggle though (maybe we could use the config predictable=false for that).

would it help to also support cos(30°) ?

I like that idea. On my keyboard the character ° is hard to find, so I myself will probably just keep typing deg, but it reads very nicely, and applications like a calculator could provide a button for it 👍

josdejong avatar Mar 23 '22 08:03 josdejong

One more (wild?) idea: currently the mathjs repo offers two setups "full" and "plain number". I can imagine we would provide a new setup "calculator", which offers just basic arithmetic functions, implements this angle config option, and wraps the trigonometric functions to support the config option, like in the example https://mathjs.org/examples/browser/angle_configuration.html.html

josdejong avatar Mar 23 '22 08:03 josdejong

the response is a number 0.5235987755982987, which is "just" in rad. I would love to return a unit unit('0.5235987755982987 rad'), so there cannot be a mistake in that an

Well the fact is that "rad" is precisely a unitless unit -- it has no dimension. So it should be that acos(sqrt(3)/2) to deg returns 30 deg. If it's not that way already, we should be able to make it so without any harm or risk. In other words "1 rad" is precisely the same mathematical entity as 1, for all purposes.

gwhitney avatar Mar 23 '22 15:03 gwhitney

One more (wild?) idea:

I like this idea better than the guard one (it's easier to admit selectively than to weed out) especially if you're willing to have calculator mode not support complex numbers (so we don't have to worry about changing the behavior of exp).

gwhitney avatar Mar 23 '22 16:03 gwhitney

👍

Well the fact is that "rad" is precisely a unitless unit -- it has no dimension. So it should be that acos(sqrt(3)/2) to deg returns 30 deg. If it's not that way already, we should be able to make it so without any harm or risk. In other words "1 rad" is precisely the same mathematical entity as 1, for all purposes.

Good point. Yeah so we could allow converting any number into a unit Deg, so acos(...) to deg would work. That's an interesting idea.

josdejong avatar Mar 24 '22 11:03 josdejong

we could allow converting any number into a unit Deg

Scratch that, darn. What I said was mathematically reasonable, but it doesn't work in the presence of the unit system mathjs has:

sin(tau/4) = sin((tau/4) rad) = sin(90 deg) = 1

and

asin(1) = tau/4 and asin(1) = (tau/4) rad = 90 deg

but

90 deg/secs = (tau/4 rad/secs) = 1/4 hertz

whereas

(tau/4) / secs = 1.57... hertz

So the "pure number" tau/4 unfortuately does not work the same as the "angle" (tau/4) rad in all contexts :-(

So the best we can do is is something like asin(1) rad to deg which does already work properly.

Incidentally, the conversion 720 deg/secs to hertz does not currently work in mathjs; should I file a separate issue about that?

gwhitney avatar Mar 25 '22 17:03 gwhitney

wow 🤯 that makes sense. Well, yes, let's leave it up to the user to specify the unit rad.

josdejong avatar Mar 28 '22 10:03 josdejong