Error On 32 bit architecture device (iPhone 5c,iPhone 4s)
Opened this issue · 8 comments
Integer literal '8000000000' overflows when stored into 'Int'
for those who installed this lib via CocoaPods and don't need support for older device there is the same error when archiving.
To avoid this error one can add following to the end of Podfile
post_install do |installer| installer.pods_project.targets.each do |target| target.build_configurations.each do |config| config.build_settings['ARCHS'] = 'arm64' end end end
I was using version 2.0, and I had problems with 32bit architecture devices.
After updating recent version, I got this 8000000000 literal error. But I had to support these devices. So I went back to version 2.0.
Problem was somehow (I don't know why) UInt64.multipliedFullWidth(by: r)
doesn't work properly and produced this runtime error: Thread 1: Fatal error: Operation is not supported
So I wrote my own multipliedFullWidth
function using 32-bit operation:
public func multiplyFullWidth(_ ab: UInt64, _ cd: UInt64) -> (hi: UInt64, lo: UInt64) {
let a: UInt32 = UInt32(ab >> 32)
let b: UInt32 = UInt32(ab & 0xFFFFFFFF)
let c: UInt32 = UInt32(cd >> 32)
let d: UInt32 = UInt32(cd & 0xFFFFFFFF)
let (ach, acl) = a.multipliedFullWidth(by: c)
let (adh, adl) = a.multipliedFullWidth(by: d)
let (bch, bcl) = b.multipliedFullWidth(by: c)
let (bdh, bdl) = b.multipliedFullWidth(by: d)
var lo: UInt64 = UInt64(bdh) << 32 + UInt64(bdl)
var hi: UInt64 = UInt64(ach) << 32 + UInt64(acl) + UInt64(adh) + UInt64(bch)
var overflow = false
(lo, overflow) = lo.addingReportingOverflow(UInt64(adl) << 32)
if overflow { hi += 1 }
(lo, overflow) = lo.addingReportingOverflow(UInt64(bcl) << 32)
if overflow { hi += 1 }
return (hi, lo)
}
and modified code like
(mulHi, mulLo) = l.multipliedFullWidth(by: r)
into
if (MemoryLayout<Int>.size == MemoryLayout<Int32>.size) {
//print("32-bit architecture")
(mulHi, mulLo) = multiplyFullWidth(l, r)
} else {
//print("64-bit architecture")
(mulHi, mulLo) = l.multipliedFullWidth(by: r)
}
There were three multiplyFullWidth()
calls in the code, So I replaced them all, and now it works fine.
As far as I know, iOS 11 started to exclude 32-bit devices. But those devices are still working, and developers should consider supporting them. Devices running on iOS8 still exist, and many apps are targetting those old iOSs.
So can you support those devices? You can use the above codes. Honestly I did not see the recent version change, but I believe you can support them modifying some little code.
I hope this can help.
@scgyong Submit a PR and I'll merge it.
Instead of changing every instance of
(mulHi, mulLo) = l.multipliedFullWidth(by: r)
You could have the architecture check inside of multipliedFullWidth
func multipliedFullWidthDigit(by multiplicand: Digit) -> (Digit, Digit)
{
if (MemoryLayout<Int>.size == MemoryLayout<Int32>.size) {
let a: UInt32 = UInt32(self >> 32)
let b: UInt32 = UInt32(self & 0xFFFFFFFF)
let c: UInt32 = UInt32(multiplicand >> 32)
let d: UInt32 = UInt32(multiplicand & 0xFFFFFFFF)
let (ach, acl) = a.multipliedFullWidth(by: c)
let (adh, adl) = a.multipliedFullWidth(by: d)
let (bch, bcl) = b.multipliedFullWidth(by: c)
let (bdh, bdl) = b.multipliedFullWidth(by: d)
var lo: UInt64 = UInt64(bdh) << 32 + UInt64(bdl)
var hi: UInt64 = UInt64(ach) << 32 + UInt64(acl) + UInt64(adh) + UInt64(bch)
var overflow = false
(lo, overflow) = lo.addingReportingOverflow(UInt64(adl) << 32)
if overflow { hi += 1 }
(lo, overflow) = lo.addingReportingOverflow(UInt64(bcl) << 32)
if overflow { hi += 1 }
return (hi, lo)
}
let (lLo, lHi) = (self % DigitHalfBase, self / DigitHalfBase)
let (rLo, rHi) = (multiplicand % DigitHalfBase, multiplicand / DigitHalfBase)
let K = (lHi * rLo) + (rHi * lLo)
var resLo = (lLo * rLo) + ((K % DigitHalfBase) * DigitHalfBase)
var resHi = (lHi * rHi) + (K / DigitHalfBase)
if resLo >= DigitBase
{
resLo -= DigitBase
resHi += 1
}
return (resLo, resHi)
}
No?
(above method untested)
Honestly I didn't try to understand the codes like Limb
and Digit
. I just recognized those are aliased to UInt64
.
And multipliedFullWidthDigit(by:)
is defined in the extension of Digit
, but the code I modified is for UInt64.multipliedFullWidth(by:)
defined in Swift > Math > Integers. I'm not sure your code above would work.
According to your suggestion, architecture check can be done in my function multiplyFullWidth()
. But I think If a developer doesn't want to support 32-bit architecture devices, he/she also would not want to check the int length at runtime.
So, It would be great if there is compile-time check if the target is for 32-bit, and if it's true, runtime check should be done. And, what is the cost of MemoryLayout<Int>.size == MemoryLayout<Int32>.size
? Is it ignorable or should be checked once at startup?
Additionally, I don't know how 8_000_000_000 literal thing (and others if exist) can be modified for 32-bit architecture.
I think I know too little to submit some code. Can you please do that?
I'll look at it in more detail and if I submit a PR I'll tag you in it.
@twodayslate thanks a lot
Hi, is there any progress on this? A small fraction of our users aren’t able to create XLM accounts because of this issue.
@woudini I haven't started. Feel free to submit a PR
edit:// I probably won't be working on this - getting harder to test 32bit stuff since everything is 64... any tips to properly test are welcomed.