Skip to content

Conversation

quickfur
Copy link
Member

*/
char[] toOctalString() const
{
auto predictLength = 8*BigDigitBits / 3;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps you meant to use the actual length here.
Otherwise, the following code gives a range check error in biguintcore.d on line 1588:

import std.array, std.bigint, std.range, std.stdio;
void main () {
    auto a = BigInt ("1" ~ ("0".repeat (10000).join ("")));
    writefln ("%o", a);
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An assertion may be added to check that exactly 0, 1, or 2 characters of the predicted length are wasted.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, I wasn't paying attention and failed to actually multiply by data.length. Fixed.

@quickfur
Copy link
Member Author

Hmph, actually, assert(0 <= firstNonZero && firstNonZero <= 3); is wrong because if the BigInt has a lot of leading zeroes, firstNonZero may be quite large, up to floor(BigDigitBits/3).

@quickfur
Copy link
Member Author

No worries, I fixed the problem. Hopefully it will pass now. Thanks for finding all the problems!

@quickfur
Copy link
Member Author

Actually, even that assumption is not necessarily true, if the upper words of the BigInt are zero. I'm not sure if the code will ever generate such a BigInt, but the assert will trigger if this ever happens. I think it's safer to just take out the assert.

@GassaFM
Copy link
Contributor

GassaFM commented Feb 13, 2016

With the current assertion, the following passes now (32-bit):

    BigInt c = 1;
    foreach (step; 0..1000) {
        writefln ("%o", c);
        c *= 2;
    }

So perhaps the statement is right.

@quickfur
Copy link
Member Author

Maybe try c /= 2 after your loop to see if the code ever produces a BigInt with zeroes in the upper words?

@GassaFM
Copy link
Contributor

GassaFM commented Feb 13, 2016

Yeah, if "no leading zero words" is not explicitly guaranteed somewhere, the assertion is still wrong and should be taken out.

@GassaFM
Copy link
Contributor

GassaFM commented Feb 13, 2016

A descending loop also works fine:

    foreach (step; 0..1000)
    {
        writefln ("%o", c);
        c /= 2;
    }

But who knows what else won't work :) .

If leading zero words ever appear, or will appear, this particular assertion would be a wrong place to signal that anyway.

@quickfur
Copy link
Member Author

I glanced through the various operations, and it seems that a lot (all?) of them allocate new arrays for storing the result of operations. I'm not sure how accurate the array size estimates are, whether there might be leading zero words or not. So better leave the assert out.

@quickfur
Copy link
Member Author

Hmm, autotester is failing... I wonder if there's some problems with the length prediction code??

@GassaFM
Copy link
Contributor

GassaFM commented Feb 13, 2016

Found while trying to test this PR: https://issues.dlang.org/show_bug.cgi?id=15678

@quickfur
Copy link
Member Author

Fixed: #3995

Carried bits in last word must be output at the end.

Add unittest for 3rd/4th word no-carry boundary.

Implement 'o' format specifier in BigInt.toString().
@quickfur
Copy link
Member Author

Rebased.

#3995 has been merged; any other issues?

@DmitryOlshansky
Copy link
Member

LGTM

@quickfur
Copy link
Member Author

ping random reviewers @andralex @JakobOvrum @schveiguy @klickverbot @DmitryOlshansky
This has been sitting here for a while. Is it a go or a no-go?

size_t penPos = buff.length - 1;
size_t lastNonZero = buff.length - 1;

pragma(inline) void output(int digit) @nogc nothrow
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this accepting int? Every call to this is with an unsigned type, and most of them are size_t.

May be a good reason, but I feel like this should be size_t or ptrdiff_t -- i.e. whatever is natural for the architecture.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right, this should not accept a signed integer type. I refrained from using size_t because the range of parameters should always be < 8 (otherwise there is a bug). No need to use 64 bits when 32 bits already suffices (in fact, just 4 bits already suffice, but requiring anything smaller than 32 bits requires ugly casts and doesn't necessarily make the generated asm any better).

@schveiguy
Copy link
Member

Implementation looks sound. Is there a reason you didn't implement fromOctalString?

@quickfur
Copy link
Member Author

I'm leaving fromOctalString to a followup PR because I wanted to avoid merge conflicts with #3876 .

@schveiguy
Copy link
Member

Auto-merge toggled on

@schveiguy schveiguy merged commit 630e227 into dlang:master Mar 31, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants