Coreen Stupka
Coreen Stupka

Reputation: 45

Find the biggest digit

FUNCTION FBIG(N NUMBER) RETURN NUMBER 
IS
  R NUMBER; 
  M NUMBER;
  S NUMBER;

  BEGIN
  M := N;
  WHILE M>0 LOOP  
  R := MOD(M,10); 
  M := FLOOR(M/10);   
  S := GREATEST(R,M); 
   END LOOP;
 RETURN S;
  END FBIG;
END;
/

EXEC DBMS_OUTPUT.PUT_LINE(FBIG(47839));

Find the biggest digit if the 47839. 9 is the input value. I tried to take the last digit by MOD and remove the decimal by FLOOR.

Upvotes: 0

Views: 400

Answers (3)

MT0
MT0

Reputation: 167962

Just convert the number to a string in PL/SQL and test each character until you get to the decimal point:

CREATE FUNCTION FBIG(N NUMBER) RETURN NUMBER 
IS
  s CONSTANT VARCHAR2(4000) := TO_CHAR( n );
  c CHAR(1);
  m CHAR(1) := NULL;
BEGIN
  FOR i IN 1 .. LENGTH( s ) LOOP
    c := SUBSTR( s, i, 1 );
    IF c = '.' THEN
      EXIT;
    ELSIF m IS NULL OR c > m THEN
      m := c;
    END IF;
  END LOOP;
  RETURN TO_NUMBER( m );
END FBIG;
/

Why your function does not work:

M := N;
WHILE M>0 LOOP  
  R := MOD(M,10); 
  M := FLOOR(M/10);   
  S := GREATEST(R,M); 
END LOOP;

You are overwriting S with each loop so the return value will only consider the most-significant digit as the previous ones will have been overwritten. So for N = 47839.9 the steps it goes through are:

  1. R = 9.9, M = 4783, S = 4783
  2. R = 3, M = 478, S = 478
  3. R = 8, M = 47, S = 47
  4. R = 7, M = 4, S = 7
  5. R = 4, M = 0, S = 4

and then it will return 4.

How to fix your function:

CREATE FUNCTION FBIG(N NUMBER) RETURN NUMBER 
IS
  s NUMBER(1,0) := NULL;
  r NUMBER(1,0) := NULL;
  m NUMBER      := FLOOR( ABS( n ) );
BEGIN
  WHILE m > 0 LOOP
    r := MOD( m, 10 );
    IF s IS NULL OR r > s THEN
      s := r;
    END IF;
    m := ( m - r ) / 10;
  END LOOP;
  RETURN s;
END FBIG;
/

Upvotes: 2

Boneist
Boneist

Reputation: 23578

The reason why your original code is not working is because a) your M will always be greater or equal to R until the very last loop (when M becomes 0), and b) you're not comparing the current value to the previous value of S.

Your code can be tweaked to work as follows:

FUNCTION fbig(n NUMBER) RETURN NUMBER IS
  r NUMBER;
  m NUMBER;
  s NUMBER := 0;

BEGIN
  m := n;
  WHILE m > 0
  LOOP
    r := MOD(m, 10);
    m := floor(m / 10);
    s := greatest(r, s);
  END LOOP;
  RETURN s;
END fbig;
/

There are only two changes I needed to make, changing the greatest to check between s and r, and also to assign 0 to s right at the start (otherwise s will always be null, regardless of the value of r).

Upvotes: 2

Littlefoot
Littlefoot

Reputation: 142705

How about another approach? Split number to digits and select the largest of them:

SQL> create or replace function fbig (n number)
  2  return number
  3  is
  4    retval number;
  5  begin
  6    select max(num)
  7    into retval
  8    from (select substr(to_char(n), level, 1) num
  9          from dual
 10          connect by level <= length(n)
 11         );
 12
 13    return retval;
 14  end;
 15  /

    Function created.

SQL> select fbig(47839) res1,
  2         fbig(125.774) res2
  3  from dual;

      RES1       RES2
---------- ----------
         9          7

SQL>

Upvotes: 1

Related Questions