Does RealModule only support Float?

I spent a long time in a swift playground trying to get answers for functions found in the Numerics package. Finally, I tried Float instead of Double and it worked. Is this expected or am I missing something

import SwiftUI
import RealModule


var greeting = "Hello, playground"

var y: Float = 4.01
var z: Double = 4.01
let x = log10(y)
let xx = log10(z)
let a = log(y)
let aa = log(z)
print(y, z, x, xx, a, aa)

gives me:

4.01 4.01 0.6031444 4.01 1.3887913 4.01

Top-level log and log10 are C library functions that you’ve imported here via SwiftUI.

Unless I’m mistaken, Swift Numerics doesn’t shadow these, so you’re not using the library at all. To use the RealModule facilities you’ve imported, call Float.log, Double.log, etc.

5 Likes

Xiaodi is exactly right; you're getting the log10 function from the Darwin module via SwiftUI, and also hitting a bug present in some Xcodes where the lldb/playground environment doesn't know about a special kind of "resolver" symbol and so calls the wrong symbol in the math library¹.


¹ there are a few different log10 implementations on macOS / x86 for different HW feature sets. The resolver function is normally called at the first use to pick the right one; it returns the address of the function as an integer value to the dyld stub binder. LLDB didn't know about this, and thinks that the resolver is log10; since it doesn't touch the floating-point registers, the input is left unmodified in xmm0, and that's what gets printed out. This has been fixed for a little while though, so I'm slightly surprised that you're seeing it--what Xcode version are you using?

2 Likes

Thanks @xwu and @scanon

I am new to using packages, so your answers have really helped.
I am using Xcode 13.1 on macOS Monterey 12.0.1.
My iMac's processor is 3 GHz Quad-Core Intel Core i5 (KadyLake, I think?)

Before, option-clicking in Xcode didn't point to where it found log, log10. Now Float.log10 and Double.log10 did point to the RealModule Float+Real.swift file.
I removed the import SwiftUI and it no longer found log, log10 from the Darwin module.

However, Double.log10(x) still just returns the argument and NOT the correct answer:

let x = Float.log10(4.01)
let xx = Double.log10(4.01)
print(x, xx)

Gives: 0.6031444 4.01

The declaration of Float.log10 in the above snippet is:

  @_transparent
  public static func log10(_ x: Float) -> Float {
    libm_log10f(x)
  }

I know in C, the "f" in libm_log10f is for a float. The declaration of Double.log10 in the above snippet is:

@_transparent
  public static func log10(_ x: Double) -> Double {
    libm_log10(x)
  }

For my real project, Float is fine, but it is definitely disconcerting to see the wrong answer for Double in this toy playground.

Hmmmm, sometimes rebooting the Mac resolves some strange Xcode errors...

Right, this is because Double.log10 ends up mapping to the same log10 function from the system math library.

I am surprised to see this on 13.1. Are you using a toolchain you downloaded from swift.org, or Xcode's swift? If you're using a toolchain, what version?

The bug is specific to lldb/playgrounds, so you won't have the problem in your "real project".

No toolchain. (I don't know how to use toolchains, on purpose, that is.)

Ok, a colleague was able to confirm that the bug is present in 13.1, but happily it seems to be fixed in the 13.2 beta that I'm using. If you have a chance to try out 13.2 in your environment and confirm, please do.

I hesitate to use beta versions, but can do that at some point if this becomes a show stopper for me.

I did confirm you were correct that it is an lldb/playground problem only, since in that same workspace where the playground answer is incorrect:

import RealModule
import SwiftUI

struct ContentView: View {
    var body: some View {
        Text("It is \(Double.log10(4.01))")
            .padding()
    }
}

gives the correct answer in the Preview window. Whew! And thanks again!

1 Like