Forum Discussion

Frost's avatar
Frost
Frequent Visitor
9 years ago
Solved

Number to Binary

Is it possible to convert numbers to binary data in Power BI?

  • MarcelBeug's avatar
    MarcelBeug
    9 years ago

    I addition to my previous respons.

     

    Some of the things I realized recently, is that:

    an "if ... then ... else"  statement with big chunks of code like above, is not required.

     

    Thanks to concept of "Lazy Evaluation" in Power Query, you can just put in the code without if...then...else.

    Intead, the choice is made later. In the example below: in the Result step.

     

    So the inner part of the previous function (which is the actual function without documentation), can be rewritten as:

     

        fnNBC = (input as anynonnull, base as number, optional outputlength as number) as any =>
        let
            //    input = 10,
            //    base = 2,
            //    outputlength = null,
            Base16 = "0123456789ABCDEF",
            Base32 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567",
            Base64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
            Lookups = List.Zip({{16,32,64},{Base16,Base32,Base64}}),
            Lookup = Text.ToList(List.Last(List.Select(Lookups,each _{0} <= List.Max({16, base}))){1}),
            InputToList = Text.ToList(input),
    
            // This part will be executed if input is text:
                Reversed = List.Reverse(InputToList),
                BaseValues = List.Transform(Reversed, each List.PositionOf(Lookup,_)),
                Indexed = List.Zip({BaseValues, {0..Text.Length(input)-1}}),
                Powered = List.Transform(Indexed, each _{0}*Number.Power(base,_{1})),
                Decimal = List.Sum(Powered),
            // So far this part
    
            // This part will be executed if input is not text:
                Elements = 1+Number.RoundDown(Number.Log(input,base),0),
                Powers = List.Transform(List.Reverse({0..Elements - 1}), each Number.Power(base,_)),
                ResultString = List.Accumulate(Powers,
                                              [Remainder = input,String = ""], 
                                              (c,p) => [Remainder = c[Remainder] - p * Number.RoundDown(c[Remainder] / p,0),
                                                        String = c[String] & Lookup{Number.RoundDown(c[Remainder]/p,0)}])[String],    
                PaddedResultString = if outputlength = null then ResultString else Text.PadStart(ResultString,outputlength,Lookup{0}),
            // So far this part
    
            Result = if input is text then Decimal else PaddedResultString
        in
            Result

     

9 Replies

    • Frost's avatar
      Frost
      Frequent Visitor

      Thanks for the input. I tried using the approach to convert the number '52'  to binary, but can't the expected output of 00110100. Is there another feature I'm missing to use numbers instead of hex or text?

       

      • MarcelBeug's avatar
        MarcelBeug
        Community Champion

        Some time ago I shared a great function on another forum.

         

        With this function - fnNumberBaseConversion - you can convert numbers to (almost) any base and vice versa.

        Disclaimer: as far as I know, the function works fine, but I can't give any guarantees.

         

        Screen shot with the parameters to get 00110100 from 52:

         

        Result:

         

        And the code, with complete documentation:

         

        let 
            Documentation =
            [Documentation.Category =    "Custom Function",
             Documentation.Description = "Function created by Bemint to convert numbers from or to a specific base",
             Documentation.Examples =    { [Description = "Convert 10 to binary",
                                           Code = "fnNumberBaseConversion(10, 2)",
                                           Result = "10100"],
                                           [Description = "Convert 123456 to hexadecimal with a result length of minimal 8",
                                           Code = "fnNumberBaseConversion(123456, 16, 8)",
                                           Result = "0001E240"]},
             Documentation.LongDescription =
                        "fnNumberBaseConversion converts a number to a base string or vice versa.
                         Supported bases are 2 thru 16, 32 and 64.
                         Input is either an integer > 0 that will be converted to a base string or a base string that will be converted to a number.
                         Optionally, outputlength can be supplied to have resulting base strings padded to the desired length"],
        
            fnNBC = (input as anynonnull, base as number, optional outputlength as number) as any =>
            let
                //    input = 10,
                //    base = 2,
                //    outputlength = null,
                Base16 = "0123456789ABCDEF",
                Base32 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567",
                Base64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
                Lookups = List.Zip({{16,32,64},{Base16,Base32,Base64}}),
                Lookup = Text.ToList(List.Last(List.Select(Lookups,each _{0} <= List.Max({16, base}))){1}),
                InputToList = Text.ToList(input),
                Result = if input is text
                then
                let
                    Reversed = List.Reverse(InputToList),
                    BaseValues = List.Transform(Reversed, each List.PositionOf(Lookup,_)),
                    Indexed = List.Zip({BaseValues, {0..Text.Length(input)-1}}),
                    Powered = List.Transform(Indexed, each _{0}*Number.Power(base,_{1})),
                    Decimal = List.Sum(Powered)
                in
                    Decimal
                else
                let
                    Elements = 1+Number.RoundDown(Number.Log(input,base),0),
                    Powers = List.Transform(List.Reverse({0..Elements - 1}), each Number.Power(base,_)),
                    ResultString = List.Accumulate(Powers,
                                                  [Remainder = input,String = ""], 
                                                  (c,p) => [Remainder = c[Remainder] - p * Number.RoundDown(c[Remainder] / p,0),
                                                            String = c[String] & Lookup{Number.RoundDown(c[Remainder]/p,0)}])[String],    
                    PaddedResultString = if outputlength = null then ResultString else Text.PadStart(ResultString,outputlength,Lookup{0})
                in
                    PaddedResultString
            in
                Result,
            // Create FunctionType with metadata at function type level:
            FunctionType = Type.ForFunction([ReturnType = type any, Parameters = [input = type anynonnull, base = type number, outputlength = type number]], 2) meta Documentation,
            fnNumberBaseConversion = Value.ReplaceType(fnNBC,FunctionType)
        in
            fnNumberBaseConversion