Swift-BigInt icon indicating copy to clipboard operation
Swift-BigInt copied to clipboard

Error On 32 bit architecture device (iPhone 5c,iPhone 4s)

Open patelgaurav4u opened this issue 6 years ago • 8 comments

Integer literal '8000000000' overflows when stored into 'Int'

patelgaurav4u avatar Mar 22 '18 10:03 patelgaurav4u

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

Yaro812 avatar Apr 10 '18 09:04 Yaro812

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 avatar Sep 06 '18 02:09 scgyong

@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)

twodayslate avatar Sep 06 '18 03:09 twodayslate

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?

scgyong avatar Sep 06 '18 05:09 scgyong

I'll look at it in more detail and if I submit a PR I'll tag you in it.

twodayslate avatar Sep 06 '18 23:09 twodayslate

@twodayslate thanks a lot

scgyong avatar Sep 06 '18 23:09 scgyong

Hi, is there any progress on this? A small fraction of our users aren’t able to create XLM accounts because of this issue.

kwgithubusername avatar Nov 08 '18 20:11 kwgithubusername

@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.

twodayslate avatar Nov 08 '18 21:11 twodayslate