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

printf and complex numbers #346

Closed
ViralBShah opened this issue Jan 18, 2012 · 16 comments
Closed

printf and complex numbers #346

ViralBShah opened this issue Jan 18, 2012 · 16 comments
Assignees

Comments

@ViralBShah
Copy link
Member

How do we handle complex numbers in printf? It would be nice to handle them. Does C99 say anything on the topic?

julia> printf("%8.2f\n", randn()+im*randn())
type error: typeassert: expected Real, got Complex128
in anonymous, no file
in printf, /Users/viral/julia/j/printf.j:315
in run_repl, /Users/viral/julia/j/client.j:22
in _start, /Users/viral/julia/j/client.j:130
@ghost ghost assigned StefanKarpinski Jan 18, 2012
@JeffBezanson
Copy link
Sponsor Member

Good example of why we could use standard formatting functions that can be overloaded for different types of numbers.

@StefanKarpinski
Copy link
Sponsor Member

I guess the expected behavior here would be to print each component with the given format specifier? That seems reasonable enough, at least from the user interface perspective. I'll have to think about how best to do this. It implies that you want not only your formatting function as a whole to be a generic function, which can be specialized on different argument combinations, but also that you want each individual formatter to be generic as well so that it can have overloaded definitions.

@StefanKarpinski
Copy link
Sponsor Member

@JeffBezanson, is your idea that we just have a printf_f function that takes arguments maybe something like this:

printf_f(x::Float, width::Int, precision::Int, flags::ASCIIString) = ...
printf_f(x::Integer, width::Int, precision::Int, flags::ASCIIString) = ...
printf_f(x::Complex, width::Int, precision::Int, flags::ASCIIString) = ...

Two concerns about this:

  • compared to generating a custom function, it limits the amount of compile-time code specialization that can be done for each format specifier — you still need to handle width, precision and flags at print time.
  • it doesn't allow easy generalization of what to do with, e.g., complex numbers — there would have to be a complex method defined for every numeric format specifier, when what we really want to do is more something like a generic rule that any numeric format specifier be applied to the components of a complex number.

Another approach is to just say that the user has to deal with complex numbers. Writing this is not so bad:

z = randn()+im*randn()
printf("%8.2f+%8.2fim\n", real(z), imag(z))

@StefanKarpinski
Copy link
Sponsor Member

An interesting generalization along similar lines would be doing things like this:

v = cumsum(randn(100))
printf("% 3d: %8.2f\n", 1:length(v), v)

which would automatically iterate over the given arguments in tandem. However, this could be done at the level of writing additional methods for printf itself rather than for the format function. It would allow the optimization of generating the format function only once for the entire vector.

@StefanKarpinski
Copy link
Sponsor Member

I think a slight level of indirection can accomplish what's requested here. The f"% 3d: %8.2f\n" part constructs an array of single-argument formatting functions that operate on the expected core type, in this case Real (all our numeric specifiers can handle integers or floating point numbers equally well directly). Let's call the individual formatting functions p1 and p2. Then the main function emitted for the format string looks like this:

function (x1,x2)
  printf1number(p1,x1)
  print(": ")
  printf1number(p2,x2)
  print('\n')
end

It is specialized for the number of arguments, the specific generated functions p1 and p2, and the stuff printed between that. The function printf1number has a core definition that is just this:

printf1number(p::Function, x::Real) = p(x)

That is, for real values, it just applies the formatting function p to x, which prints the value formatted. However, we can add a method for complex numbers too:

function printf1number(p::Function, x::Complex)
  p(real(x))
  print("+")
  p(imag(x))
  print("im")
end

This one method would enable all numeric format specifiers to print complex numbers.

@JeffBezanson
Copy link
Sponsor Member

Unfortunately in that scenario I can no longer guarantee that the let optimization will occur. It seems manually writing printf("%8.2f+%8.2fim\n", real(z), imag(z)) or just using string(z) for the standard representation may be the best option. Let's go with that for now.

@StefanKarpinski
Copy link
Sponsor Member

Yeah, I think that's fair. While very generic, this is an overly complicated approach for something that can be handled more flexibly on the user side.

@ViralBShah
Copy link
Member Author

It just seems inelegant for complex number printing to be handled in user code.

@JeffBezanson
Copy link
Sponsor Member

Easiest would probably be to have a format character for it, but I'm not sure there are any letters left! :)

@ViralBShah
Copy link
Member Author

What if we use the same one for reals, but print complex numbers when those are passed in - %f ?

-viral

On Jan 19, 2012, at 10:30 AM, JeffBezanson wrote:

Easiest would probably be to have a format character for it, but I'm not sure there are any letters left! :)


Reply to this email directly or view it on GitHub:
#346 (comment)

@JeffBezanson
Copy link
Sponsor Member

Then what about Rational?

@ViralBShah
Copy link
Member Author

Can't %f be a stand-in for all kinds of numbers passed in? It really just says that interpret the input as floating point with number of digits to print. Alternatively, for rational, we may just use %d.

-viral

On Jan 19, 2012, at 11:05 AM, JeffBezanson wrote:

Then what about Rational?


Reply to this email directly or view it on GitHub:
#346 (comment)

@JeffBezanson
Copy link
Sponsor Member

Personally, I suspect printf just has too many features, making it harder than necessary to figure out how to factor the functionality.

@StefanKarpinski
Copy link
Sponsor Member

Personally, I suspect printf just has too many features, making it harder than necessary to figure out how to factor the functionality.

Having struggled with implementing and then reimplementing it better for well over a week now, I can attest to this being true. I don't think we should add to the problem. I don't see where the benefit from being able to print complex values using %f is. There's all sorts of features like field width that stop making sense then. Does the width apply to each component of a complex value or to the whole thing? What if I don't like the way Julia chooses to format complex numbers? I don't want spaces around the + in the middle... I want to use i instead of im... I want to print complex numbers as a pair in parens. Once you head down this road, there's no end to feature requests. The printf spec is a standard, well-established, if overly complicated feature. We can implement it with some obvious improvements to usability and speed, but I think extending it in any substantial way is a bad idea.

@StefanKarpinski
Copy link
Sponsor Member

For example, our printf can do these tricks:

julia> sprintf("%d",realmax())
"179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368"

julia> sprintf("%f",typemax(Int64))
"9223372036854775807.000000"

julia> sprintf("%f",typemax(Uint64))
"18446744073709551615.000000"

@ViralBShah
Copy link
Member Author

Closing this since the discussion clearly shows that we'd rather not add more functionality to printf.

StefanKarpinski pushed a commit that referenced this issue Feb 8, 2018
Backport bswap method for complex numbers.
cmcaine pushed a commit to cmcaine/julia that referenced this issue Nov 11, 2022
To allow rendering the track's documents on the v3 website, we're introducing a docs/config.json file.

This commit adds the docs/config.json file.
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

3 participants