Skip to content

Commit

Permalink
Add strformat support for Complex numbers (#22924)
Browse files Browse the repository at this point in the history
Before this change strformat used the generic formatValue function for
Complex numbers. This meant that it was not possible to control the
format of the real and imaginary components of the complex numbers.

With this change this now works:
```nim
import std/[complex, strformat]
let c = complex(1.05000001, -2.000003)
echo &"{c:g}"
# You now get: (1.05, -2)
# while before you'd get a ValueError exception (invalid type in format string for string, expected 's', but got g)
```

The only small drawback of this change is that I had to import complex
from strformat. I hope that is not a problem.

---------

Co-authored-by: Angel Ezquerra <[email protected]>
  • Loading branch information
AngelEzquerra and AngelEzquerraAtKeysight authored Nov 10, 2023
1 parent 60597ad commit 52784f3
Showing 1 changed file with 36 additions and 1 deletion.
37 changes: 36 additions & 1 deletion lib/pure/complex.nim
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ runnableExamples:
{.push checks: off, line_dir: off, stack_trace: off, debugger: off.}
# the user does not want to trace a part of the standard library!

import std/math
import std/[math, strformat]

type
Complex*[T: SomeFloat] = object
Expand Down Expand Up @@ -399,4 +399,39 @@ func `$`*(z: Complex): string =

result = "(" & $z.re & ", " & $z.im & ")"

proc formatValueAsTuple(result: var string; value: Complex; specifier: string) =
## Format implementation for `Complex` representing the value as a (real, imaginary) tuple.
result.add "("
formatValue(result, value.re, specifier)
result.add ", "
formatValue(result, value.im, specifier)
result.add ")"

proc formatValueAsComplexNumber(result: var string; value: Complex; specifier: string) =
## Format implementation for `Complex` representing the value as a (RE+IMj) number
result.add "("
formatValue(result, value.re, specifier)
if value.im >= 0 and not specifier.contains({'+', '-'}):
result.add "+"
formatValue(result, value.im, specifier)
result.add "j)"

proc formatValue*(result: var string; value: Complex; specifier: string) =
## Standard format implementation for `Complex`. It makes little
## sense to call this directly, but it is required to exist
## by the `&` macro.
## For complex numbers, we add a specific 'j' specifier, which formats
## the value as (A+Bj) like in mathematics.
if specifier.len == 0:
result.add $value
elif 'j' in specifier:
let specifier = if specifier.contains({'e', 'E', 'f', 'F', 'g', 'G'}):
specifier.replace("j")
else:
# 'The 'j' format defaults to 'g'
specifier.replace('j', 'g')
formatValueAsComplexNumber(result, value, specifier)
else:
formatValueAsTuple(result, value, specifier)

{.pop.}

0 comments on commit 52784f3

Please sign in to comment.