Integer Logarithm

12

1

Objective

Take \$a \in ℤ_{>1}\$ and \$b \in ℤ_+\$ as inputs. Write a function \$f\$ such that:

$$ f(a,b) = \left\{ \begin{array}{ll} \log_ab & \quad \text{if} \space \log_ab \in ℚ \\ -1 & \quad \text{otherwise} \end{array} \right. $$

Rules

  • Types and formats of the inputs doesn't matter.

  • Type and format of the output doesn't matter either, but the fraction must be irreducible. In C++, std::pair<int,unsigned> is an example. (Regarding logarithms, the numerator and the denominator need not to be arbitrary-length integers.)

  • Regardless of whether the input type can handle arbitrary-length integers, the algorithm must be "as if" it were handling those. So using floating-point numbers is implicitly banned.

  • If \$a\$ and \$b\$ aren't in the sets as specified above, the challenge falls in don't care situation.

  • \$f\$ may be curried or uncurried.

  • As this is a code-golf, the shortest code in bytes wins.

Test cases

a   b   => answer
-----------------
2   8   => 3/1
3   9   => 2/1
8   2   => 1/3
9   3   => 1/2
4   8   => 3/2
64  256 => 4/3
999 1   => 0/1
-----------------
2   7   => -1
10  50  => -1
5   15  => -1

Dannyu NDos

Posted 2020-02-13T23:03:52.153

Reputation: 2 087

5Could you add some example test cases? Preferably ones where $log_ab \in \mathbb{Q} \setminus \mathbb{Z}$ – Value Ink – 2020-02-13T23:16:24.087

3@PostRockGarfHunter One example is $ \log_4 8 = 3/2 $. – Bubbler – 2020-02-13T23:19:23.180

they must be able to represent arbitrary-length integers This is a rather odd requirement, since it unfairly penalizes languages which don't have access to arbitrary-precision integer type (many of them don't even have a thing called "import"). Instead, we usually say "use the most natural number type for the language, but the underlying algorithm should generalize to higher numbers." – Bubbler – 2020-02-13T23:35:40.660

@Bubbler I added that requirement to implicitly ban floating-point numbers, but to think about it, that's better. – Dannyu NDos – 2020-02-13T23:38:23.123

7

It looks like you posted this from the Sandbox with edits that are only in the live version, which is unfortunate. Had you waited, I would have pointed out that you still don't have any test cases, which I had commented to remind you to add. And Bubbler might have raised their point about integer size in the Sandbox, which would give you more time to think how to address it, and I might have asked to clarify your new "as if" rule, which I think is unclear as it stands. See Things to avoid: Assuming you've addressed sandbox feedback.

– xnor – 2020-02-13T23:59:15.107

@xnor Well... You know what is more unfortunate? The Mathematica answer apparently use builtin exact arithmetic. This is not what I intended. To admit it, I didn't even want a code golf. I just wanted to see some art of integer arithmetics. So farewell, I'm closing this challenge. – Dannyu NDos – 2020-02-14T00:16:17.107

Do we have to output as a fraction or can we output as a float? – Lyxal – 2020-02-14T00:18:36.950

Answers

1

Sledgehammer, 11 bytes

Alternatively, 83 bits.

I ended up forgetting to actually answer this with Sledgehammer for a while...

⣜⢍⡪⡱⣰⡵⠅⣧⣼⣅⣸

Compressed from this Wolfram Language code:

If[NumberQ[x1 = Log[Input[], Input[]]], x1, -1]

, where NumberQ is a built-in that checks whether Log has returned an actual number and not a symbolic expression, i.e. when it is rational.

my pronoun is monicareinstate

Posted 2020-02-13T23:03:52.153

Reputation: 3 111

8

Mathematica, 47 45 43 29 bytes SBCS

If[NumberQ[c=#~Log~#2],c,-1]&

You can try it online!

Thanks to @J42161217 for saving me a total of 16 bytes!!

RGS

Posted 2020-02-13T23:03:52.153

Reputation: 5 047

@J42161217 weird it works in the pattern guard but not inside the if – RGS – 2020-02-14T00:24:47.957

29 bytes. This one works! Although OP doesn't like solutions like this at all (read main comments above). But after all, this is code-golf – J42161217 – 2020-02-14T01:19:35.743

@J42161217 wow incredible!!! – RGS – 2020-02-14T06:49:42.813

Fed floating point numbers ( Print[f[1.2,1.44]] ) it outputs the right value.... almost ( 2.0000000000000004 ). Is "Log" a floating point function? – David G. – 2020-02-14T22:47:03.497

OK. I will admit to being impressed by Mathematica's Log operator(?). It makes me wonder if I can't write something faster... – David G. – 2020-02-15T01:34:41.623

5

Python 3, 103 101 97 bytes

Saved 2 bytes thanks to Kevin Cruijssen!!!
Saved 4 bytes thanks to Value Ink!!!

from math import*
def f(a,b):
 l=log(b,a)
 n,m=l.as_integer_ratio()
 return -1if a**n-b**m else l

Try it online!

Noodle9

Posted 2020-02-13T23:03:52.153

Reputation: 2 776

Times out on 8,4 (expected result 2/3) among other things. Nice idea for the fractional exponent check, though. – Value Ink – 2020-02-14T01:23:53.547

@ValueInk What a shame - guess using as_integer_ratio like this isn't quite up to Mathematica standards! T_T – Noodle9 – 2020-02-14T10:43:21.627

Yeah, it's the floating point precision error causing problems, which Mathematica probably knows how to get around... I didn't get it submitted before the question closed but I tried something similar with Ruby's to_r which is equivalent -- while that function does return without timing out, because of the precision problems it was giving the wrong number. BTW, use log(b,a) next time. It won't help you with this question because of the aforementioned floating point problem, but could be useful for another problem later! – Value Ink – 2020-02-14T11:03:08.860

@ValueInk A golfs a golf, nice one - thanks! :-) Maybe I can sort out the floating point issue. – Noodle9 – 2020-02-14T11:13:44.113

My solution (which I will post if this gets reopened) was basically to walk through the rationals manually by using the idea that $x > 1 \implies x^{1/x} \notin \mathbb{Z}$ to limit the denominator of the fraction to numbers up to $a$. Wolframalpha of $x^{1/x}$

– Value Ink – 2020-02-14T11:24:23.927

5

Charcoal, 88 82 bytes

≔Eθ⟦⟧ζ≔²ηW⊖⌈θ¿⌊﹪θη≦⊕ηUMθ⎇﹪κηκ∧⊞O§ζλη÷κηFζFι⊞υκUMυEζ№λιUMυ÷ι⊟Φ⊕⌈ι∧λ¬⌈﹪ιλ¿›⌈υ⌊υ-1I⊟υ

Try it online! Link is to verbose version of code. Takes input as a list in [value, base] order and outputs numerator and denominator. Edit: Saved 6 bytes by simplifying my check for exclusive factors. Explanation:

≔Eθ⟦⟧ζ≔²ηW⊖⌈θ¿⌊﹪θη≦⊕ηUMθ⎇﹪κηκ∧⊞O§ζλη÷κη

Factorise both numbers by trial division.

FζFι⊞υκ

Collect the factors from both inputs, in case some factors are only present in one of them.

UMυEζ№λιUMυ÷ι⊟Φ⊕⌈ι∧λ¬⌈﹪ιλ

Divide the multiplicity of each factor in both the base and the value by their GCD.

¿›⌈υ⌊υ-1

If this is not unique then output -1.

I⊟υ

If it is unique then output it.

Neil

Posted 2020-02-13T23:03:52.153

Reputation: 95 035

5

05AB1E, 18 17 bytes

-1 byte thanks to Kevin Cruijssen

Ó0ζD€¿÷ʒOĀ}DËiнë®

Try it online!

Ó                   # prime factorize each input
 0ζ                 # zip the factorizations together with filler 0
                    # for each pair of exponents:
    D€¿             #  get the gcd
       ÷            #  divide both by the gcd (reducing the fraction)
        ʒ  }        # filter the pairs, keep only those where:
         O          #  the sum
          Ā         #  is not 0
            DËi     # if all the resulting pairs are equal:
               н    #  output the first pair
                ë   # otherwise:
                 ®  #  output -1

Grimmy

Posted 2020-02-13T23:03:52.153

Reputation: 12 521

1-1 by using D€¿÷ instead of εD¿÷} – Kevin Cruijssen – 2020-02-14T14:16:21.260

4

Python 3, 94 79 76 bytes

Nothing clever here; this is the obvious brute force approach.

Edit: Unified return point and switched to lambda syntax.

Edit 2: Shaved off three bytes due to @xnor's next trick and rules clarification.

lambda a,b:next(((i,j)for i in range(b)for j in range(1,a)if a**i==b**j),-1)

Try it online!

Yonatan N

Posted 2020-02-13T23:03:52.153

Reputation: 497

1

This is a great place to use the next syntax for generators: Try it online!. By the way, by default, you don't have to write f= for non-recursive functions.

– xnor – 2020-02-15T05:18:22.367

@xnor Didn't know about that second next parameter. Nice one! – Yonatan N – 2020-02-15T22:41:52.493

2

bc, 110 bytes

define f(a,b){
c=0
d=1
while(0!=e=a^c-b^d){if(a<2^d){print"-1";return}
if(e>1)d=d+1 else c=c+1}
print c,"/",d}

Try it online!

As with a number of my solutions, it outputs its answer and returns 0, which the test code ignores.

The use of scale= in the provided input is only so the expected value can be passed in. (You can't have a string value in bc.) The code is strictly integer... provided you pass in integers. The code may fail if a or the needed root of a is less than two. (See two failing samples in TIO.)

David G.

Posted 2020-02-13T23:03:52.153

Reputation: 541

2

JavaScript (Node.js),  72  68 bytes

Takes input as (a)(b), where \$a\$ and \$b\$ are BigInts. Returns either [numerator, denominator] or \$-1\$.

a=>g=(b,p=0n,q=1n)=>p>b?-1:(d=a**p-b**q)?g(b,d>0?++q&&p:-~p,q):[p,q]

Try it online!

How?

We start with \$p=0\$ and \$q=1\$. We iteratively increment \$q\$ if \$a^p>b^q\$ or increment \$p\$ if \$a^p<b^q\$, until \$a^p=b^q\$ (success) or \$p>b\$ (no solution).

Arnauld

Posted 2020-02-13T23:03:52.153

Reputation: 111 334

1

Ruby, 72 bytes

->a,b{n,d=[*1..a*b].product([*1..a]).find{|n,d|a**n==b**d};n ?n/1r/d:-1}

Try it online!

Value Ink

Posted 2020-02-13T23:03:52.153

Reputation: 10 608