Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for complex numbers #355

Open
IvanUkhov opened this issue Aug 15, 2016 · 12 comments
Open

Add support for complex numbers #355

IvanUkhov opened this issue Aug 15, 2016 · 12 comments
Milestone

Comments

@IvanUkhov
Copy link

IvanUkhov commented Aug 15, 2016

Hi,

According to the standard (section 6.7.2, page 111), the C language provides the _Compex type specifier, which allows one to work with complex numbers using the following types:

  • float _Complex,
  • double _Complex, and
  • long double _Complex.

I’m curious if there are any particular objections against adding the following types to libc:

  • c_float_complex and
  • c_double_complex.

The reason I ask is that there are C APIs that make use of complex numbers, and, in order interact with them from Rust, one has to create complex types him/herself instead of just importing them from libc. Thank you!

Regards,
Ivan

@alexcrichton
Copy link
Member

I'd be game! I hear though that there are weird ABI implications though we may have to deal with?

@IvanUkhov
Copy link
Author

I’d love to help with the implementation, but I’m not sure if I’m competent enough to do it, and I’m not aware of any ABI implications. The way I see it is that each of the two types can be defined using an array or a struct:

pub type c_float_complex = [f32; 2];

#[repr(C)]
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct c_float_complex {
    pub re: f32,
    pub im: f32,
}

I don’t think one should implement any arithmetic traits and such. We don’t want to write num-complex here; libc is low level, bare minimum. If it’s all it takes, I can open a pull request.

@alexcrichton
Copy link
Member

Right yeah we'd just want the type definitions and related functions if any here. I'd want to be 100% sure about the ABI though (with it being equivalent to such a struct) before merging.

@IvanUkhov
Copy link
Author

IvanUkhov commented Aug 16, 2016

I perfectly understand your concern. I’ve tried to read a bit about the layout of complex numbers in C. According to both C99 (section 6.2.5, paragraph 13) and C11 (section 6.2.5, paragraph 13),

Each complex type has the same representation and alignment requirements as an array
type containing exactly two elements of the corresponding real type; the first element is
equal to the real part, and the second element to the imaginary part, of the complex
number.

(Note that I give links to drafts as they are the only ones publicly available.)

Regarding C++ (not our case, but just to make the picture more complete), the layout is not guaranteed by C++03, but it is by C++1x (section 26.4, paragraph 4), which is done in order to have a better interoperability with C:

If z is an lvalue expression of type cv std::complex<T> then:
— the expression reinterpret_cast<cv T(&)[2]>(z) shall be well-formed,
reinterpret_cast<cv T(&)[2]>(z)[0] shall designate the real part of z, and
reinterpret_cast<cv T(&)[2]>(z)[1] shall designate the imaginary part of z.
Moreover, if a is an expression of type cv std::complex<T>* and the expression a[i] is well-defined for an integer expression i, then:
reinterpret_cast<cv T*>(a)[2*i] shall designate the real part of a[i], and
reinterpret_cast<cv T*>(a)[2*i + 1] shall designate the imaginary part of a[i].

Regarding related functions, C99 defines the following: cabs, carg, cimag, creal, conj, cproj, cexp, clog, csqrt, cpow, csin, ccos, ctan, casin, cacos, catan, csinh, ccosh, ctanh, casinh, cacosh, and catanh. Each one has two more versions: one for float _Complex (add an f suffix) and one for long double _Complex (add an l suffix). The most basic ones are creal and cimag. One can also see that C’s convention is to use “real” and “imag” for referring to the real and imaginary components, respectively (in case you prefer to define a complex number as a struct with two fields whose names should be adequately chosen; I personally would use just an array).

Please let me know what you think about all this. Thank you.

@alexcrichton
Copy link
Member

Ah yeah I'm just specifically thinking of this issue: rust-lang/rfcs#793. If we handle that then seems good to me!

@IvanUkhov
Copy link
Author

IvanUkhov commented Aug 17, 2016

Thanks for the link! I see now what the problem is. But if it can’t be done conveniently and reliably without additional support from the compiler, there is no point to discuss it here. Probably you don’t want to see those workarounds in libc. Or, do you have a different opinion?

@IvanUkhov
Copy link
Author

I see in .travis.yml that you have set up a good target coverage. It should make it much easier to find a #[cfg(…)]-based solution that works at least across those targets. If all pull requests are automatically tested, I could open one and tune it until Travis gives the green light. We can then see how it looks and decide if it’s worth it.

@alexcrichton
Copy link
Member

Yeah I'm just not sure if we can do this without compiler support. If we can, great! If not, we may want to wait for that. It may be best to actually prototype this support outside of libc itself and once it's proven we could merge?

Right now the CI doesn't actually test the ABI, just that the definitions in C and Rust agree. So it may not be enough to get a green build on this repo :(

@IvanUkhov
Copy link
Author

IvanUkhov commented Aug 17, 2016

Yeah I'm just not sure if we can do this without compiler support. If we can, great! If not, we may want to wait for that. It may be best to actually prototype this support outside of libc itself and once it's proven we could merge?

Can you please give an example that cannot be solved using conditional compilation via attributes so that I don’t waste time if it’s really hopeless?

Right now the CI doesn't actually test the ABI, just that the definitions in C and Rust agree. So it may not be enough to get a green build on this repo :(

I meant that I would write a couple of such tests first. For instance, one could call some of those functions that I previously mention and check that the output is as expected.

@alexcrichton
Copy link
Member

Oh if it's all solvable with #[cfg] attributes then that's all libc's domain! I don't personally know how much of a problem this is, nor how it'd be solved across platforms. If something works though then it works and that's good for me!

@gnzlbg
Copy link
Contributor

gnzlbg commented Feb 21, 2019

cc @emilio how does bindgen handle complex numbers? and what is your opinion about adding these to libc?

@emilio
Copy link

emilio commented Feb 21, 2019

See rust-lang/rust-bindgen#72 and related. Bindgen generates something like struct Complex<T> { re: T, im: T } ATM. That gets correct layout, but not 100% sure whether it's correct ABI-wise, would need to check. Adding them to libc seems like a good idea, if it's well defined.

@tgross35 tgross35 added this to the 1.x milestone Aug 29, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants