Swift: initializer 'init(_:)' requires that 'Decimal' conform to 'BinaryInteger' - ios

I'm trying to create a function that calculates and returns compound interest. The variables are having different data types. Whenever I run the program I get an error initializer 'init(_:)' requires that 'Decimal' conform to 'BinaryInteger'. The following is my code:
import Foundation
class Compound{
var p:Double
var t:Int
var r:Double
var n:Int
var interest:Double
var amount:Double
init(p:Double,t:Int,r:Double,n:Int){
self.p = p
self.t = t
self.r = r
self.n = n
}
func calculateAmount() -> Double {
amount = p * Double(pow(Decimal(1 + (r / Double(n))),n * t))
return amount
}
}
The Error:
error: initializer 'init(_:)' requires that 'Decimal' conform to 'BinaryInteger'
amount = p * Double(pow(Decimal(1 + (r / Double(n))),n * t))
^
After looking at a similar problem I've also tried the following technique but I'm still getting the same error
func calculateAmount() -> Double {
let gg:Int = n * t
amount = p * Double(pow(Decimal(1 + (r / Double(n))),Int(truncating: gg as NSNumber) ))
return amount
}
How to solve this?

It would be easier to use the Double func pow(_: Double, _: Double) -> Double instead of using Decimal func pow(_ x: Decimal, _ y: Int) -> Decimal considering that you want to return a Double:
#discardableResult
func calculateAmount() -> Double {
amount = p * pow(1 + (r / Double(n)), Double(n) * Double(t))
return amount
}

Related

Custom SHA256 hash calculation fails on anything but an empty String

I am trying to create my own hashing framework/library, but I've stumbled across an issue. When I calculate the SHA256 hash of an empty string, the hash is calculated successfully, but when I calculate it for anything else, it fails. Can someone help me figure out why?
As provided by Wikipedia, when performed online and using python, this hash matches.
let h = SHA256(message: Data("".utf8))
let d = h.digest()
// e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
print(d)
But 'Hello world' does not
let h = SHA256(message: Data("Hello world".utf8))
let d = h.digest()
// ce9f4c08f0688d09b8061ed6692c1d5af2516c8682fad2d9a5d72f96ba787a80
print(d)
// Expected:
// 64ec88ca00b268e5ba1a35678a1b5316d212f4f366b2477232534a8aeca37f3c
I hope someone can help me. SHA256 implementation below:
/*
First 32 bits of the fractional parts of the
square roots of the first 8 primes 2..19.
*/
fileprivate let kSHA256H0: UInt32 = 0x6a09e667
fileprivate let kSHA256H1: UInt32 = 0xbb67ae85
fileprivate let kSHA256H2: UInt32 = 0x3c6ef372
fileprivate let kSHA256H3: UInt32 = 0xa54ff53a
fileprivate let kSHA256H4: UInt32 = 0x510e527f
fileprivate let kSHA256H5: UInt32 = 0x9b05688c
fileprivate let kSHA256H6: UInt32 = 0x1f83d9ab
fileprivate let kSHA256H7: UInt32 = 0x5be0cd19
/*
First 32 bits of the fractional parts of the
cube roots of the first 64 primes 2..311.
*/
fileprivate let kSHA256K: [UInt32] = [
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
]
/// Shift the value of x n amount to the right.
/// - Parameters:
/// - x: The value to shift.
/// - n: The amount to shift by.
/// - Returns: The shifted value.
fileprivate func shiftRight(_ x: UInt32, _ n: UInt32) -> UInt32 { x >> n }
/// Rotate the value of x n amount of times.
/// - Parameters:
/// - x: The value to rotate.
/// - y: The amount to rotate by.
/// - Returns: The rotated value.
fileprivate func rotateRight(_ x: UInt32, _ y: UInt32) -> UInt32 { (x >> (y & 31)) | (x << (32 - (y & 31))) }
/// Split data into chunks of specified size.
/// - Note: This function will not pad or append data
/// to make sure all the chunks are equal in size.
/// - Parameters:
/// - data: The data to split.
/// - size: The size of a chunk.
/// - Returns: An array containing chunks of specified size (when able).
fileprivate func chunk(_ data: Data, toSize size: Int) -> [Data] {
stride(from: 0, to: data.count, by: size).map {
data.subdata(in: $0 ..< Swift.min($0 + size, data.count))
}
}
public class SHA256 {
/// The pre-processed data.
fileprivate let message: Data
fileprivate var hash = [
kSHA256H0, kSHA256H1, kSHA256H2, kSHA256H3,
kSHA256H4, kSHA256H5, kSHA256H6, kSHA256H7
]
public init(message: Data) {
self.message = Self.preProcess(message: message)
}
fileprivate static func preProcess(message: Data) -> Data {
let L = message.count * 8 // Original message length in bits.
var K = 0 // Required padding bits.
while (L + 1 + K + 64) % 512 != 0 {
K += 1
}
var padding = Data(repeating: 0, count: K / 8)
padding.insert(0x80, at: 0) // Insert 1000 0000 into the padding.
var length = UInt64(L).bigEndian
return message + padding + Data(bytes: &length, count: 8)
}
public func digest() -> Data {
let chunks = chunk(message, toSize: 64)
for chunk in chunks {
var w = [UInt32](repeating: 0, count: 64) // 64-entry message schedule array of 32-bit words.
// Copy the chunk into first 16 words w[0..15] of the schedule array.
for i in 0 ..< 16 {
let sub = chunk.subdata(in: i ..< i + 4)
w[i] = sub.withUnsafeBytes { $0.load(as: UInt32.self) }.bigEndian
}
// Extend the first 16 words into the remaining 48 words w[16..63] of the schedule array.
for i in 16 ..< 64 {
let s0 = rotateRight(w[i - 15], 7) ^ rotateRight(w[i - 15], 18) ^ shiftRight(w[i - 15], 3)
let s1 = rotateRight(w[i - 2], 17) ^ rotateRight(w[i - 2], 19) ^ shiftRight(w[i - 2], 10)
w[i] = s1 &+ w[i - 7] &+ s0 &+ w[i - 16]
}
// Create some working variables.
var a = hash[0]
var b = hash[1]
var c = hash[2]
var d = hash[3]
var e = hash[4]
var f = hash[5]
var g = hash[6]
var h = hash[7]
// Compress function main loop.
for i in 0 ..< 64 {
let S1 = rotateRight(e, 6) ^ rotateRight(e, 11) ^ rotateRight(e, 25)
let ch = (e & f) ^ (~e & g)
let T1 = h &+ S1 &+ ch &+ kSHA256K[i] &+ w[i]
let S0 = rotateRight(a, 2) ^ rotateRight(a, 13) ^ rotateRight(a, 22)
let maj = (a & b) ^ (a & c) ^ (b & c)
let T2 = S0 &+ maj
h = g
g = f
f = e
e = d &+ T1
d = c
c = b
b = a
a = T1 &+ T2
}
hash[0] &+= a
hash[1] &+= b
hash[2] &+= c
hash[3] &+= d
hash[4] &+= e
hash[5] &+= f
hash[6] &+= g
hash[7] &+= h
}
return hash.map {
var num = $0.bigEndian
return Data(bytes: &num, count: 4)
}.reduce(Data(), +)
}
}
Turns out, I was creating the wrong sub data to construct my UInt32's from to create the message schedule array. (The first couple of lines in the .digest() function)
The old one was
let sub = chunk.subdata(in: i ..< i + 4)
The new one is
let sub = chunk.subdata(in: i * 4 ..< (i * 4) + 4)
This resolves the issue

Σ Calculation in iOS SDK

I am working on a financial app where I have to perform a calculation. Finance team provide me below formula for calculation as below image
[![enter image description here][1]][1]
But I am unable to found how to perform below operation in Swift or Objective-C.
n t-1
Σ (1+i)
t=1
Can you please help me providing an idea of the above calculation?
I also read this link but not interested to use the third party.
Swift's reduce function was made for this:
(1...n).reduce(0) { (currentResult, t) -> Decimal in
currentResult + pow(1 + i, t - 1)
}
If we crack it down you have to find summation of (1 + i) ^ (t -1) where t varies from 1 to n.
Equivalent function will be
func evaluteSummation(n: Int, i: Int ) -> Int {
int sum = 0
for t in 1...n {
sum += pow(1 + i, t - 1)
}
return sum
}
You can do code like below.
func calculatePMT(targetValue : Double, interestRate : Double, time: Int) -> Double {
let term = 1.0 + interestRate
var denominator = 0.0
for t in 0..<time {
let p = pow(term, Double(t))
denominator += p
}
return targetValue / denominator
}
let targetValue = 100000.0
let interestRate = 5.0
let time = 4
let pmt = calculatePMT(targetValue: targetValue, interestRate: interestRate, time: time)
print(pmt)

Inconsistent swift behavior

I am new to Swift.
I have following code
class ViewController: UIViewController {
let var1: Double = 0.0
let var2: Int = 0
override func viewDidLoad() {
super.viewDidLoad()
let someObject = TestViewController(x: 20, total: 30, taxPact: 40, subtotal: 50)
var x = 1 + 1.0 /* COMPILER IS FINE WITH ADDING INT AND DOUBLE */
print("sum is \(var1 + var2)") /* COMPILER COMPLAINS HERE BINARY OPERATOR + CANNOT BE APPLIED */
}
Why do we see such inconsistent behavior?
The error message is unrelated to string interpolation, this
let var1: Double = 0.0
let var2: Int = 0
var x = var1 + var2 // error: binary operator '+' cannot be applied to operands of type 'Double' and 'Int'
does not compile either, and the reason is that there is no +
operator which adds an Int to a Double and
Swift does not implicitly convert types. You have to convert explicitly,
e.g.
var x = var1 + Double(var2)
print("sum is \(var1 + Double(var2))")
Your other statement
var x = 1 + 1.0
compiles because both Int and Double (and some more types)
conform to the IntegerLiteralConvertible protocol,
so the literal 1 can be both a Int literal
and a Double literal. Here the compiler chooses 1 to be a
Double because that is the only choice for which a suitable
+ operator exists.

How to Typecast in Swift?

I'm working on a custom path for UIBezierPath, and I'm getting the "Cannot assign a value of type (CGFloat) to a value of type CGFloat." I think it's because there is some issue with typecasting? How can I fix this? The warnings are popping up for the "X = (b2 - b1) / (m1 - m2)" line and "Y = m1 * X + b1" line.
func lineIntersection(m1: CGFloat, b1: CGFloat, m2: CGFloat, b2: CGFloat, inout X: CGFloat, inout Y: CGFloat) -> Bool {
if m1 == m2 {
return false
} else if X = (b2 - b1)/(m1 - m2) {
return true
} else if Y = m1 * X + b1 {
return true
} else {
return false
}
}
I'll be calling this function in another function later on
func xxx() {
var outX = CGFloat()
var outY = CGFloat()
lineIntersection(oldSlope, b1: oldIntercept, m2: newSlope, b2: newIntercept, X: &outX, Y: &outY)
}
Swift doesn't have zero as a "false" value, you need to explicitly compare with != 0 in the ifs. Also, move the assignments to separate lines instead of doing it as part of the condition.
Floating point equality comparisons are not reliable except in a few special cases, and this is not likely to be one of them.
I would remove the inout parameters and return an optional CGPoint, i.e., -> CGPoint?. Return nil for false, and the CGPoint intersection for true.
Resulting function (I've removed the equality checks altogether; the floating point division by zero is not dangerous, we can check for Inf/NaN later):
func lineIntersection(m1 m1: CGFloat, b1: CGFloat, m2: CGFloat, b2: CGFloat) -> CGPoint? {
let x = (b2 - b1) / (m1 - m2)
let y = m1 * x + b1
return y.isFinite ? CGPoint(x: x, y: y) : nil
}
Use at the calling location would be something like:
if let intersection = lineIntersection(m1: m1, b1: b1, m2: m2, b2: b2) {
// use intersection.x and intersection.y
}
As for the literal question of how to typecast (although this was not the issue here), you can init even "basic types" with something like CGFloat(value), which results in a type conversion by "creating" a new CGFloat from value. Several types also have alternative ways to specify how exactly the conversion happens, e.g., Int32(truncatingBitPattern: largerInteger) takes the lowest 32 bits as they are, whereas just Int32(largerInteger) would crash if it over- or underflows. Casting as such is done with as (known to succeed at compile time), as? (try casting at runtime, nil on failure), as! (try casting at runtime, assert success).

Cannot Invoke '^' with an argument list of type '($T27, IntegerLiteralConvertible)'

func FindDistance(currentLatitude: Double, currentLongtitude: Double, compareLatitude: Double, compareLongtitdue: Double) -> Double {
var dlon = compareLongtitdue - currentLongtitude
var dlat = compareLatitude - currentLatitude
let WorldRadius = 6371
var a = sin(dlat/2)^2 + cos(currentLatitude) * cos(compareLatitude) * sin(dlon/2)^2
var c = 2 * atan2(sqrt(a), sqrt(1-a))
var d = WorldRadius * c
}
println(FindDistance(11.583431, 104.920141, 11.584966, 104.918569))
There is an Error in Line in Variable "a". said 'Cannot Invoke '^' with an argument list of type '($T27, IntegerLiteralConvertible)'.
I guess you want to use pow(x,y) function which returns x raised to the power of y.
So in order to access this function you need to import Darwin first and rewrite code as follow:
import Darwin
func FindDistance(currentLatitude:Double, currentLongtitude:Double, compareLatitude:Double, compareLongtitdue:Double) -> Double {
var dlon = compareLongtitdue - currentLongtitude
var dlat = compareLatitude - currentLatitude
let WorldRadius: Double = 6371
var a = pow(sin(dlat/2), 2) + cos(currentLatitude) * cos(compareLatitude) * pow(sin(dlon/2),2)
var c = 2 * atan2( sqrt(a), sqrt(1-a) )
var d = WorldRadius * c
return d
}

Resources