summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAngel Ezquerra <AngelEzquerra@users.noreply.github.com>2023-11-10 05:29:55 +0100
committerGitHub <noreply@github.com>2023-11-10 05:29:55 +0100
commit52784f32bbb6c764eb67a1abdbbbd9f54dc6030e (patch)
tree2c6aa1f94785e52f65d7e7142297289a94dc80b0
parent60597adb1019174fe190ff84e46284a72a8b1ae2 (diff)
downloadNim-52784f32bbb6c764eb67a1abdbbbd9f54dc6030e.tar.gz
Add strformat support for Complex numbers (#22924)
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 <angel_ezquerra@keysight.com>
-rw-r--r--lib/pure/complex.nim37
1 files changed, 36 insertions, 1 deletions
diff --git a/lib/pure/complex.nim b/lib/pure/complex.nim
index 5304d0930..87b0670d1 100644
--- a/lib/pure/complex.nim
+++ b/lib/pure/complex.nim
@@ -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
@@ -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.}