Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Get direct access to magnitude #286

Open
hgourvest opened this issue Apr 21, 2024 · 5 comments
Open

Get direct access to magnitude #286

hgourvest opened this issue Apr 21, 2024 · 5 comments
Labels
enhancement New feature or request

Comments

@hgourvest
Copy link

Is your feature request related to a problem? Please describe.
I need to convert a biginteger value to another format to be stored in a database that stores a 128 integer in two 64-bit integers. I've written two conversion functions, but as this code will be run intensively, I don't like having to create unnecessary objects using the "getBackingArrayCopy" function.

Describe the solution you'd like
I would like to have direct access to the "magnitude" value.

Describe alternatives you've considered
If you think that these conversion functions can be integrated into your library, I can also provide you with the conversion functions. The database is called Firebird SQL and uses "libtommath" to manipulate 128bit signed integers without needing to manage the sign separately.

@hgourvest
Copy link
Author

I've run extensive tests on these functions, and it's reliable.

inline fun fromBigInteger(value: BigInteger, block: (a:Long, b:Long) -> Unit) {
    val words = value.getBackingArrayCopy().toLongArray()
    val v0: Long = words[0]
    val v1: Long = if (words.size > 1) words[1] else 0L
    when (value.getSign()) {
        Sign.POSITIVE -> {
            if (v1 == 0L) {
                block(v0, 0L)
            } else {
                if (v1 % 2 == 0L) {
                    block(v0, v1 / 2)
                } else {
                    block(Long.MIN_VALUE + v0, (v1 - 1) / 2)
                }
            }
        }
        Sign.NEGATIVE -> {
            if (v1 == 0L) {
                block(-v0, -1L)
            } else {
                if (v0 == 0L) {
                    if (v1 % 2 == 0L)
                        block(0L, -(v1 / 2))
                    else
                        block(Long.MIN_VALUE, -(v1 + 1) / 2)
                } else {
                    if (v1 % 2 == 0L)
                        block(-v0, -(v1 / 2) - 1)
                    else
                        block(Long.MAX_VALUE - v0 + 1, -(v1 + 1) / 2)
                }
            }
        }
        Sign.ZERO -> ZERO
    }
}

fun toBigInteger(a: Long, b: Long): BigInteger {
    val sign = when {
        b == 0L -> if (a == 0L) Sign.ZERO else Sign.POSITIVE
        b > 0L -> Sign.POSITIVE
        else -> Sign.NEGATIVE
    }

    return when (sign) {
        Sign.POSITIVE ->
            createFromWordArray((if (a < 0)
                longArrayOf(a - Long.MIN_VALUE, b * 2 + 1)
            else if (b == 0L)
                longArrayOf(a)
            else
                longArrayOf(a, b * 2)).toULongArray(), sign)
        Sign.NEGATIVE ->
            createFromWordArray((when {
                a == 0L -> longArrayOf(0L, -b * 2)
                a == Long.MIN_VALUE -> longArrayOf(0L, (-b - 1) * 2 + 1)
                a < 0L -> {
                    val v2 = (-b - 1)
                    if (v2 == 0L)
                        longArrayOf(-a)
                    else
                        longArrayOf(-a, v2 * 2)
                }
                else ->
                    longArrayOf(Long.MAX_VALUE - a + 1, (-b - 1) * 2 + 1)
            }).toULongArray(), sign)
        Sign.ZERO -> BigInteger.ZERO
    }
}

@ionspin ionspin added the enhancement New feature or request label Apr 21, 2024
@ionspin
Copy link
Owner

ionspin commented Apr 21, 2024

Hi @hgourvest ,

I'll be traveling next two weeks so I probably won't have time to tackle this until I get back, but I'm sure we can figure something out, I feel like both options are possible, it's just deciding which approach is better.

@hgourvest
Copy link
Author

Thanks, nothing urge.

The "inline" function saves an Object because of the Lambda function, but does not allow access to the class's private elements. So if you integrate this function in "inline" mode, you'll still need to make the "magnitude" variable public.

@hgourvest
Copy link
Author

I just released the FirebirdClient library, feel free to get what you need.
https://github.com/hgourvest/Firebird-Client-KMP/blob/main/library-ext/src/commonMain/kotlin/com/progdigy/fbclient/ext/BigInteger.kt

@ionspin
Copy link
Owner

ionspin commented May 21, 2024

Thanks and congrats on the release!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants