Math operations

how to perform various maths operations like:
trigonometric functions:sin x,cos x,tan x,cot x
exponential like: 2^2,2^3
log operations
is any other operations are available ... ?
and also
how to solve divide by zero problem in rust language

If you search for e.g. sin on the official docs, you'll find this, and similar for the others. The methods are called like this:

x.sin()

Same fow pow and log. You can read through the linked doc page to see the various options available.

1 Like

how to solve divide by zero problem in rust language

You handle divide-by-zero in the same way other languages with floating point arithmetic do, by adding some sort of if x == 0.0 check.

not like that ..

in java we can use try { 24/0 } catch { System.out.print("not possible" )}
like that how to solve the problem in rust ..

if x != 0.0 {
  24.0 / x
} else {
  // handle the divide-by-zero by blowing up loudly
  panic!("Divide-by-zero");
}

So you mean "error handling / exception handling". Rust does not have exceptions, but there is a different style of error handling using types like Result and the ? operator. However, the numeric division operator is hard-wired to panic on division-by-zero, so you can't catch that using ?.

(Actually, there is panic::catch_unwind(), but that's not meant to be used for general error handling.)

So, for your specific case of division, you have to check for a 0 denominator upfront, but in other, more interesting cases (and types), you can use the ? operator.

You can use checked_div to perform the division, and then you can use normal error handling with question marks and results on that.

Just because you do it wrong in the Java world does not mean you should do it wrong in any other language. My reasoning is as follows, either:

  1. Hitting a divide by zero is a bug in your code, it is unexpected. In which case the best thing is to have your program die immediately. It's a bug, you have to fix it.

  2. Hitting divide by zero is a normal part of your program operation. Say when a user enters zero, or wherever that zero may come from. In which case you should check for it and handle it appropriately. Returning an error or whatever.

Whilst case 1) might be exceptional, you are a very good coder right?, it does not need an exception mechanism like Java and the like.

Case 2) is a normal part of program operation. It is not exceptional. Therefore it does not need an exception mechanism like Java or whatever.

Either way Rust has an excellent error handling system. What with being able to return Result types. A Java style exception mechanism is not required.

Sadly, for reasons I cannot fathom, integer divide by zero and float divide by zero behave differnetly in Rust. The first causes a panic and the program dies. The latter produces an "inf" result and the program continues. Well we just have to check for that and cause a panic or return some error. Whatever we need according to my cases above.

In general I think exceptions are a bad idea. And they are often used incorrectly. For example one might wrap try/catch around opening a file for read. If the file does not exist an exception is raised. Well, as far as I am concerned "file not found" is not an exceptional situation. It's a normal occurrence. As such exceptions are not the way to handle it.

Exceptions obfuscate the normal flow of control when used like that. It's just wrong.

Philosophically I feel that having things go wrong is the normal state of things in computing. As such handling all that should be upfront in your program. One should not try and bury it out of sight in exception handlers whilst trying to keep what you think is your main program logic flow clean of all that messy error handling stuff. That is not reality.

When things go really unexpectedly, badly, wrong, exceptions will not help you. Better to die immediately before causing more damage.

Luckily Rust with it's error handling style fits very well with my philosophy :slight_smile:

3 Likes

how to find log() and exponential like: 2^2,2^3

To support the @ZiCog's 2. case, all theose primitive integer types have method .checked_div() which returns None if the rhs is zero.

The best way is to use documentation:
https://doc.rust-lang.org/std/
https://doc.rust-lang.org/std/?search=log
https://doc.rust-lang.org/std/?search=pow

I'm pretty sure that's part of the spec for floating point numbers. From a cursory glance at the Wikipedia page:

  • Division by zero: an operation on finite operands gives an exact infinite result, e.g. , 1/0 or log(0). By default, returns ±infinity.
1 Like

Yes but that text you quote from the Wikipedia page is under a section titled "Exception handling". Except we don't get any exception/panic we get a bad result.

Somewhere along the line between hardware OS and language it was decided to be inconsistent in handling divide by zero.

Further, I have never understood why integer divide by zero, which is can only produce a bad result causes a TRAP in most of the world where as integer overflow/underflow, which can only produce a bad result, does not. Allowing your bad result to propagate.

Edit: By the way, the concept of "exact infinite result" boggles my mind. What would an inexact infinite result look like? :slight_smile:

1 Like

All math functions are here for type f64: https://doc.rust-lang.org/std/primitive.f64.html

Re. integer underflow/overflow not trapping, I think that boils down to some common hardware not supporting it and software implementation being very expensive.

IEEE-754 error handling is a bit more interesting. In principle, lots of hardware supports trapping on divide-by-zero and other floating-point mistakes, but since IEEE-754 decided in its not-so-great wisdom to make this feature optional, some hardware does not, and most hardware which supports this feature disables it by default.

As a result, compilers got used to floating-point exception traps not being enabled, and started to optimize code in a manner which changes run-time behavior when such traps are turned on. Therefore, some compilers do not support trapping floating-point exceptions at all (IIRC that's still the case for Rust's beloved LLVM backend), while others only support it at the cost of a blanket ban on many floating-point optimizations that can seriously harm performance.

Not to mention, of course, the fact that many programming languages do not provide a way to handle floating-point exceptions.

Therefore, the standard way to handle floating-point errors in the IEEE-754 world is to check return values for "error codes" (infinities, NaNs...) like it's the 70s, and cross fingers that the previous parts of your computation did not swallow the error signal before you checked it.

This whole business of returning NaNs and infs from floating point ops runs counter to the only existing Rust pattern I know, don't return errors as special values in your result, like C functions often do, rather return a Result type and include both the result and error state in it.

Sure, but then it's the same problem as integer under/overflow: if hardware doesn't help you at checking it, the checks can easily get expensive in code that does lots of arithmetic.

Yeah I know.

I don't care whose fault it is, processor, OS, language, whatever. I just marvel that after seven decades of building computers we still have these simple things that will silently produce the wrong result and continue as if nothing bad had happened.

If I ask a function/instruction/employee/whatever to do something it should do it and give back the correct result. If it cannot do it, it should let me know rather than pretend it could and give me some random result.

The situation has been so bad for so long that everyone has accepted it as OK, inevitable, just the way things are, we can never do anything about it, ever.

Grrr.. makes me mad.

I think the reason why integer division by zero has traps in common processors and why floats don't is because floats provide special values (inf, nan) that propagate through math operations. Integers on the other hand don't have any special values and therefore require traps (or some other mechanism).

And honestly I don't think that's a bad design decision. My reasoning for this is that control flow of programs is mostly dependent on integers, where a bad math operation is a logic error. On the other hand floats are by design lossy (and probably shouldn't be used to alter control flow without a lot of care about precision problems) and are mainly used for computations where a bad math operator indicates a precision problem and not a logic error.

Not to say you cannot build logic error using floats, but that really isn't what they are intended for. If your control flow depends on computations on floats you probably should think about using some symbolic math library that actually can return guaranteed correct results.

1 Like