How to determine if CGFloat is Float or Double [duplicate] - swift

This question already has answers here:
Should conditional compilation be used to cope with difference in CGFloat on different architectures?
(3 answers)
Closed 6 years ago.
Quartz uses CGFloat for its graphics. CGFloat is either Float or Double, depending on the processor.
The Accelerate framework has different variations of the same function.
For example dgetrf_ for Double's and sgetrf_ for Float's.
I have to make these two work together. Either I can use Double's everywhere and convert them to CGFloat every time I use quartz, or I can (try to) determine the actual type of CGFloat and use the appropriate Accelerate function.
Mixing CGFloat's and Double types all over my code base is not very appealing and converting thousands or millions of values to CGFloat every time doesn't strike me as very efficient either.
At this moment I would go with the second option. (Or shouldn't I?)
My question is: how do I know the actual type of CGFloat?
if ??? //pseudo-code: CGFloat is Double
{
dgetrf_(...)
}
else
{
sgetrf_(...)
}

Documentation on Swift Floating-Point Numbers:
Floating-point types can represent a much wider range of values than
integer types, and can store numbers that are much larger or smaller
than can be stored in an Int. Swift provides two signed floating-point
number types:
Double represents a 64-bit floating-point number.
Float represents a 32-bit floating-point number.
You can test using the sizeof function:
if sizeof(CGFloat) == sizeof(Double) {
// CGFloat is a Double
} else {
// CGFloat is a Float
}
Probably the easiest way to deal with this is to use conditional compilation to define a wrapper which will call the proper version:
import Accelerate
func getrf_(__m: UnsafeMutablePointer<__CLPK_integer>,
__n: UnsafeMutablePointer<__CLPK_integer>,
__a: UnsafeMutablePointer<CGFloat>,
__lda: UnsafeMutablePointer<__CLPK_integer>,
__ipiv: UnsafeMutablePointer<__CLPK_integer>,
__info: UnsafeMutablePointer<__CLPK_integer>) -> Int32 {
#if __LP64__ // CGFloat is Double on 64 bit archetecture
return dgetrf_(__m, __n, UnsafeMutablePointer<__CLPK_doublereal>(__a), __lda, __ipiv, __info)
#else
return sgetrf_(__m, __n, UnsafeMutablePointer<__CLPK_real>(__a), __lda, __ipiv, __info)
#endif
}

There is a CGFLOAT_IS_DOUBLE macro defined in Core Graphics. You can use it in Swift for direct comparison:
if CGFLOAT_IS_DOUBLE == 1 {
print("Double")
} else {
print("Float")
}
Of course, direct size comparison is also possible:
if sizeof(CGFloat) == sizeof(Double) {
}
However, since there are overloaded functions for all Float, Double and CGFloat, there is rarely a reason to inspect the size of the type.

Related

How to deal with the lack of `simd_packed_float3` in Swift

There is no simd_packed_float3 type in Swift.
Why it's a problem?
Consider this Metal struct:
struct Test{
packed_float3 x;
float y;
};
First of all, you can't calculate a buffer pointer to address the memory of y, since you can't do this:
MemoryLayout<simd_packed_float3>.size
(Not sure if stride makes sense with packed types, but anyway with simd types it always gives the same length as size on my devices)
You can't use MemoryLayout<simd_float3>.size either, since it will return 16 and not 12 like in architectures available to me for testing.
Second, if you need to write a packed_float3 value of x to the buffer you will need to write the three consecutive floats, but not a single simd type. Again, simd_float3 is not usable since it will write 0 into the forth word corrupting the memory of the next property in the struct (y).
So I've done this:
struct Float_3{
var x: Float
var y: Float
var z: Float
}
typealias simd_packed_float3 = Float_3
It seems to be a functioning solution, but I'm not sure it's not a nasty thing to do...
What problems may I encounter with this approach, and how could I be sure that it won't break on some device that I don't have?
You can define a packed struct in your bridging header:
struct __attribute__((packed)) PackedFloat3 {
float x;
float y;
float z;
};
MemoryLayout<PackedFloat3>.size == 12
MemoryLayout<PackedFloat3>.stride == 12
By the way, simd_float3 is 16 bytes everywhere, simd types have stricter alignment requirements.
You can also typedef it to packed_float3 under #ifndef #ifdef __METAL_VERSION__ to have the same spelling in Swift and MSL.
The reason to do it in bridging header instead of Swift is that you can use the same structs with same spelling in both shaders and Swift.
I'm answering this following the answers I received on the Swift forum.
Turns out that someone in the Metal team at Apple has already thought of this problem and created the MTLPacked types exactly for the types that would have irregular sizes:
MTLPackedFloat3
MTLPackedFloat4x3

What is the purpose of Float.addProduct in Swift?

What is the purpose of Float.addProduct in Swift? Are the operators Float + Float and Float * Float actually implemented using this as a base function, as in
let zero:Float = 0
func + (a:inout Float, b:Float) {
a.addProduct(1,b)
}
func * (a:inout Float, b:Float) {
0.addProduct(a,b)
}
Are + and * actually implemented using the same processor instruction that is being called with addProduct?
Float.addProduct performs an operation known as "Fused Multiply and Add", or FMA. This computes a*b + c. Importantly, though, it does so without rounding the result of a*b to a representable floating point number. As a result, FMA can result in significantly lower error than directly computing a*b+c, when properly used. It's the sort of thing where, when you need it, you'll know it.
No, regular addition and multiplication are generally not implemented through the operation this function performs; regular addition and multiplication are already available, and FMA can be significantly slower than regular multiplication and addition on some platforms.

Using arc4random_uniform to return a both whole and non whole doubles

Using Swift, I am trying to figure out how to use arc4random_uniform to return a number like 37.7. The guidance I must abide by is I must do it in a function, the random double must be between 0 - 300. I have been able to build a function that randomly returns doubles between the range but can't find anything that will lead me to outputting random non whole numbers
//function to randomly generate a double number like 105.3
func makeRandDbl() -> Double {
let randGenerator: Double = Double(arc4random_uniform(301))
print(randGenerator)
return randGenerator
}
makeRandDb()
To generate a Double in the range 0.0 to 300.0 (with one digit following the decimal):
Double(arc4random_uniform(3001))/10.0
You can extend this to more decimal places. For two decimal places (0.00 to 300.00):
Double(arc4random_uniform(30001))/100.0
For three decimal places (0.000 to 300.000):
Double(arc4random_uniform(300001))/1000.0
This has the advantage of being able to actually generate whole values. In the first case 10% of the numbers will be whole. In the second case 1% of the numbers will be whole. And in the third, 0.1% of the numbers will be whole.
This is your function, I believe:
extension Double {
/// Generates a random `Double` within `0.0...1.0`
public static func random() -> Double {
return random(0.0...1.0)
}
/// Generates a random `Double` inside of the closed interval.
public static func random(interval: ClosedInterval<Double>) -> Double {
return interval.start + (interval.end - interval.start) * (Double(arc4random()) / Double(UInt32.max))
}
}
Usage example:
Double.random(0...300)
It is taken from RandomKit library - it looks very useful for various purposes.
One approach would be to convert the result of arc4random_uniform to double, divide the result by UInt32.max, and then multiply the result by 300.
let rand = 300 * Double(arc4random_uniform(UInt32.max)) / Double(UInt32.max)
This would produce a value between 0 and 300, inclusive. The number of possible values that you are going to get is UInt32.max.

Division returns something different in functions

Paste the following code into a playground:
5.0 / 100
func test(anything: Float) -> Float {
return anything / 100
}
test(5.0)
The first line should return 0.05 as expected. The function test returns 0.0500000007450581. Why?
It has nothing to do with functions. Your first example is using type Double which represents floating point numbers more precisely by using 64 bits. If you were to change your second example to:
func test(anything: Double) -> Double {
return anything / 100
}
test(5.0)
You would get the result you expect. Float uses only 32 bits of data, thus it provides a less precise representation of the number. Also, floating point numbers are stored as binary values and frequently are only an approximation of the base 10 representation. That is why 0.05 is showing up as 0.0500000007450581 when stored as a Float.

Can I safely use CGFloat to hold Float64 or Float32 values?

I have an CGFloat property and sometimes I get a return value of type Float64 or also of type Float32. Could I store both safely to CGFloat?
From the headers:
// CGBase.h
typedef float CGFloat;
// MacTypes.h
typedef float Float32;
typedef double Float64;
So CGFloat and Float32 are both floats while Float64 is a double so you would lose precision.
(Edit to clarify: this is for 32 bit systems such as the iPhone. If you are building for 64 bit, CGFloat is defined as a double.)
It's best practice to always try and store scalar values in the same type as you received them because the precision of scalar types changes with the hardware.
CGFloat isn't always guaranteed to be the same size on all current and future hardware. If you substitute another type for it or use it to store another type, your code made break somewhere down the road.
You might gain or lose precision when a new iPhone/iPad comes out or the code might break if you try to port it to Macs.