xyz => x+y+z

Язык Visual Basic на платформе .NET.

Модераторы: Ramzes, Sebas

MIT
Мега гуру
Мега гуру
Аватара пользователя
 
Сообщения: 2211
Зарегистрирован: 17.09.2006 (Вс) 22:46

xyz => x+y+z

Сообщение MIT » 24.02.2009 (Вт) 21:48

Есть string цифрового содержания, например "12341234", цифры которого надо сложить.

Первое, что пришло на ум - это:
Код: Выделить всё
    Dim str As String = "12341234", ret As Integer
            For x As Integer = 0 To str.Length - 1
                ret += (str.Substring(x, 1))
            Next
Немножко подумав (все-таки со стрингом не забалуешь), модифицировал до
Код: Выделить всё
    Dim str As String = "12341234", ret As Integer
            For x As Integer = 0 To str.Length - 1
                ret += Asc(str.Substring(x, 1))
            Next
            ret = ret - 48 * str.Length
Как выяснилось - не зря, такой метод, в среднем, быстрее в 4 раза.

Есть ли какие-нибудь другие, более оптимальные варианты?

З.Ы. А если в качестве входного параметра будет выступать не строка, а Integer?
Изображение
You can change your face, but can`t change your mind. No matter what you do.
Создайте еще более понятный интерфейс и мир создаст еще более тупого юзера. (с) Баш

RayShade
Scarmarked
Scarmarked
Аватара пользователя
 
Сообщения: 5511
Зарегистрирован: 02.12.2002 (Пн) 17:11
Откуда: Russia, Saint-Petersburg

Re: xyz => x+y+z

Сообщение RayShade » 24.02.2009 (Вт) 22:14

Естественно, первый вариант будет долгий потому что ты используешь неявное преобразование типов (не знаю, как это по научному называется), но ret += (str.Substring(x, 1)) делает именно это. Можно вообще было не париться и использовать Val(str.Substring(x, 1)) - сэкономишь на последующем вычитании.
Ну и если в качестве аргумента будет integer, то я б не парился и привел его к строке :) Ну и использовал этот же самый алгоритм :)
I don't understand. Sorry.

MIT
Мега гуру
Мега гуру
Аватара пользователя
 
Сообщения: 2211
Зарегистрирован: 17.09.2006 (Вс) 22:46

Re: xyz => x+y+z

Сообщение MIT » 24.02.2009 (Вт) 22:23

RayShade писал(а):Естественно, первый вариант будет долгий потому что ты используешь неявное преобразование типов
это понятно, оно меня собственно и смутило

RayShade писал(а):использовать Val(str.Substring(x, 1))
А как насчет CInt и Integer.Parse (строка всегда будет числовой, так что ошибка не предусмотрена по технологии)?
Изображение
You can change your face, but can`t change your mind. No matter what you do.
Создайте еще более понятный интерфейс и мир создаст еще более тупого юзера. (с) Баш

RayShade
Scarmarked
Scarmarked
Аватара пользователя
 
Сообщения: 5511
Зарегистрирован: 02.12.2002 (Пн) 17:11
Откуда: Russia, Saint-Petersburg

Re: xyz => x+y+z

Сообщение RayShade » 24.02.2009 (Вт) 22:29

О! Integer.Parse! Я про него забыл просто :) СInt/Val в топку - они там по моему оставлены для совместимости со старым бейсиком. Наверняка они его в итоге и вызывают для совместимости.
I don't understand. Sorry.

MIT
Мега гуру
Мега гуру
Аватара пользователя
 
Сообщения: 2211
Зарегистрирован: 17.09.2006 (Вс) 22:46

Re: xyz => x+y+z

Сообщение MIT » 24.02.2009 (Вт) 23:22

RayShade писал(а):Наверняка они его в итоге и вызывают для совместимости.

Val (о ужас!):
Код: Выделить всё
Public Shared Function Val(ByVal InputStr As String) As Double
    Dim ch As Char
    Dim num As Integer
    Dim num2 As Integer
    Dim num3 As Integer
    Dim length As Integer
    Dim num8 As Double
    If (InputStr Is Nothing) Then
        length = 0
    Else
        length = InputStr.Length
    End If
    Dim num4 As Integer = 0
    Do While (num4 < length)
        ch = InputStr.Chars(num4)
        Select Case ch
            Case (((ChrW(9) AndAlso ChrW(10)) AndAlso ChrW(13)) AndAlso (" "c AndAlso ChrW(12288)))
                Exit Select
        End Select
        num4 += 1
    Loop
    If (num4 >= length) Then
        Return 0
    End If
    ch = InputStr.Chars(num4)
    If (ch = "&"c) Then
        Return Conversion.HexOrOctValue(InputStr, (num4 + 1))
    End If
    Dim flag As Boolean = False
    Dim flag2 As Boolean = False
    Dim flag3 As Boolean = False
    Dim y As Double = 0
    ch = InputStr.Chars(num4)
    Select Case ch
        Case "-"c
            flag3 = True
            num4 += 1
            Exit Select
        Case "+"c
            num4 += 1
            Exit Select
    End Select
    Do While (num4 < length)
        ch = InputStr.Chars(num4)
        Dim ch3 As Char = ch
        If ((((ch3 = ChrW(9)) OrElse (ch3 = ChrW(10))) OrElse (ch3 = ChrW(13))) OrElse ((ch3 = " "c) OrElse (ch3 = ChrW(12288)))) Then
            num4 += 1
        Else
            If (ch3 = "0"c) Then
                If ((num <> 0) OrElse flag) Then
                    num8 = (((num8 * 10) + CDbl(ch)) - 48)
                    num4 += 1
                    num += 1
                Else
                    num4 += 1
                End If
                Continue Do
            End If
            If ((ch3 >= "1"c) AndAlso (ch3 <= "9"c)) Then
                num8 = (((num8 * 10) + CDbl(ch)) - 48)
                num4 += 1
                num += 1
            Else
                If (ch3 = "."c) Then
                    num4 += 1
                    If flag Then
                        Exit Do
                    End If
                    flag = True
                    num3 = num
                    Continue Do
                End If
                If ((((ch3 = "e"c) OrElse (ch3 = "E"c)) OrElse (ch3 = "d"c)) OrElse (ch3 = "D"c)) Then
                    flag2 = True
                    num4 += 1
                End If
                Exit Do
            End If
        End If
    Loop
    If flag Then
        num2 = (num - num3)
    End If
    If Not flag2 Then
        If (flag AndAlso (num2 <> 0)) Then
            num8 = (num8 / Math.Pow(10, CDbl(num2)))
        End If
    Else
        Dim flag4 As Boolean = False
        Dim flag5 As Boolean = False
        Do While (num4 < length)
            ch = InputStr.Chars(num4)
            Dim ch4 As Char = ch
            If ((((ch4 = ChrW(9)) OrElse (ch4 = ChrW(10))) OrElse (ch4 = ChrW(13))) OrElse ((ch4 = " "c) OrElse (ch4 = ChrW(12288)))) Then
                num4 += 1
            ElseIf ((ch4 >= "0"c) AndAlso (ch4 <= "9"c)) Then
                y = (((y * 10) + CDbl(ch)) - 48)
                num4 += 1
            Else
                If (ch4 = "+"c) Then
                    If flag4 Then
                        Exit Do
                    End If
                    flag4 = True
                    num4 += 1
                    Continue Do
                End If
                If ((ch4 <> "-"c) OrElse flag4) Then
                    Exit Do
                End If
                flag4 = True
                flag5 = True
                num4 += 1
            End If
        Loop
        If flag5 Then
            y = (y + num2)
            num8 = (num8 * Math.Pow(10, -y))
        Else
            y = (y - num2)
            num8 = (num8 * Math.Pow(10, y))
        End If
    End If
    If Double.IsInfinity(num8) Then
        Throw ExceptionUtils.VbMakeException(6)
    End If
    If flag3 Then
        num8 = -num8
    End If
    Select Case ch
        Case "%"c
            If (num2 > 0) Then
                Throw ExceptionUtils.VbMakeException(13)
            End If
            Return CDbl(CShort(Math.Round(num8)))
        Case "&"c
            If (num2 > 0) Then
                Throw ExceptionUtils.VbMakeException(13)
            End If
            Return CDbl(CInt(Math.Round(num8)))
        Case "!"c
            Return CDbl(CSng(num8))
        Case "@"c
            Return Convert.ToDouble(New Decimal(num8))
    End Select
    Return num8
End Function


CInt (aka ToInteger):
Код: Выделить всё
Public Shared Function ToInteger(ByVal Value As String) As Integer
    Dim num As Integer
    If (Value Is Nothing) Then
        Return 0
    End If
    Try
        Dim num2 As Long
        If Utils.IsHexOrOctValue(Value, (num2)) Then
            Return CInt(num2)
        End If
        num = CInt(Math.Round(Conversions.ParseDouble(Value)))
    Catch exception As FormatException
        Throw New InvalidCastException(Utils.GetResourceString("InvalidCast_FromStringTo", New String() { Strings.Left(Value, &H20), "Integer" }), exception)
    End Try
    Return num
End Function

Код: Выделить всё
Private Shared Function ParseDouble(ByVal Value As String) As Double
    Return Conversions.ParseDouble(Value, Nothing)
End Function

Код: Выделить всё
Private Shared Function ParseDouble(ByVal Value As String, ByVal NumberFormat As NumberFormatInfo) As Double
    Dim num As Double
    Dim cultureInfo As CultureInfo = Utils.GetCultureInfo
    If (NumberFormat Is Nothing) Then
        NumberFormat = cultureInfo.NumberFormat
    End If
    Dim normalizedNumberFormat As NumberFormatInfo = Conversions.GetNormalizedNumberFormat(NumberFormat)
    Value = Utils.ToHalfwidthNumbers(Value, cultureInfo)
    Try
        num = Double.Parse(Value, NumberStyles.Any, DirectCast(normalizedNumberFormat, IFormatProvider))
    Catch obj1 As Object When (?)
        num = Double.Parse(Value, NumberStyles.Any, DirectCast(NumberFormat, IFormatProvider))
    Catch exception2 As Exception
        Throw exception2
    End Try
    Return num
End Function


В то время, как Integer.Parse (aka Int32.Parse) "всего лишь":
Код: Выделить всё
Public Shared Function Parse(ByVal s As String) As Integer
    Return Number.ParseInt32(s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo)
End Function

Friend Shared Function ParseInt32(ByVal s As String, ByVal style As NumberStyles, ByVal info As NumberFormatInfo) As Integer
    Dim stackBuffer As Byte* = stackalloc Byte[(1 * &H72)]
    Dim number As New NumberBuffer(stackBuffer)
    Dim num As Integer = 0
    Number.StringToNumber(s, style, (number), info, False)
    If ((style And NumberStyles.AllowHexSpecifier) <> NumberStyles.None) Then
        If Not Number.HexNumberToInt32((number), (num)) Then
            Throw New OverflowException(Environment.GetResourceString("Overflow_Int32"))
        End If
        Return num
    End If
    If Not Number.NumberToInt32((number), (num)) Then
        Throw New OverflowException(Environment.GetResourceString("Overflow_Int32"))
    End If
    Return num
End Function

Private Shared Sub StringToNumber(ByVal str As String, ByVal options As NumberStyles, ByRef number As NumberBuffer, ByVal info As NumberFormatInfo, ByVal parseDecimal As Boolean)
    If (str Is Nothing) Then
        Throw New ArgumentNullException("String")
    End If
    Dim str2 As Char*
    Fixed str2 = DirectCast(str, Char*)
        Dim chPtr As Char* = str2
        Dim chPtr2 As Char* = chPtr
        If (Not Number.ParseNumber((chPtr2), options, (number), info, parseDecimal) OrElse ((CLng(((chPtr2 - chPtr) / 2)) < str.Length) AndAlso Not Number.TrailingZeros(str, CInt(CLng(((chPtr2 - chPtr) / 2)))))) Then
            Throw New FormatException(Environment.GetResourceString("Format_InvalidString"))
        End If
    End Fixed
End Sub

Private Shared Function ParseNumber(ByRef str As Char*, ByVal options As NumberStyles, ByRef number As NumberBuffer, ByVal numfmt As NumberFormatInfo, ByVal parseDecimal As Boolean) As Boolean
    Dim currencyDecimalSeparator As String
    Dim currencyGroupSeparator As String
    Dim chPtr2 As Char*
    number.scale = 0
    number.sign = False
    Dim currencySymbol As String = Nothing
    Dim ansiCurrencySymbol As String = Nothing
    Dim numberDecimalSeparator As String = Nothing
    Dim numberGroupSeparator As String = Nothing
    Dim flag As Boolean = False
    If ((options And NumberStyles.AllowCurrencySymbol) <> NumberStyles.None) Then
        currencySymbol = numfmt.CurrencySymbol
        If (Not numfmt.ansiCurrencySymbol Is Nothing) Then
            ansiCurrencySymbol = numfmt.ansiCurrencySymbol
        End If
        numberDecimalSeparator = numfmt.NumberDecimalSeparator
        numberGroupSeparator = numfmt.NumberGroupSeparator
        currencyDecimalSeparator = numfmt.CurrencyDecimalSeparator
        currencyGroupSeparator = numfmt.CurrencyGroupSeparator
        flag = True
    Else
        currencyDecimalSeparator = numfmt.NumberDecimalSeparator
        currencyGroupSeparator = numfmt.NumberGroupSeparator
    End If
    Dim num As Integer = 0
    Dim flag2 As Boolean = False
    Dim p As Char* = str
    Dim ch As Char = p(0)
    Do While True
        If ((Not Number.IsWhite(ch) OrElse ((options And NumberStyles.AllowLeadingWhite) = NumberStyles.None)) OrElse (((num And 1) <> 0) AndAlso (((num And 1) = 0) OrElse (((num And &H20) = 0) AndAlso (numfmt.numberNegativePattern <> 2))))) Then
            If (flag2 = (((options And NumberStyles.AllowLeadingSign) <> NumberStyles.None) AndAlso ((num And 1) = 0)) AndAlso (Not chPtr2 = Number.MatchChars(p, numfmt.positiveSign) Is Nothing)) Then
                num = (num Or 1)
                p = (chPtr2 - 1)
            ElseIf (flag2 AndAlso (Not chPtr2 = Number.MatchChars(p, numfmt.negativeSign) Is Nothing)) Then
                num = (num Or 1)
                number.sign = True
                p = (chPtr2 - 1)
            ElseIf (((ch = "("c) AndAlso ((options And NumberStyles.AllowParentheses) <> NumberStyles.None)) AndAlso ((num And 1) = 0)) Then
                num = (num Or 3)
                number.sign = True
            Else
                If (((currencySymbol Is Nothing) OrElse (chPtr2 = Number.MatchChars(p, currencySymbol) Is Nothing)) AndAlso ((ansiCurrencySymbol Is Nothing) OrElse (chPtr2 = Number.MatchChars(p, ansiCurrencySymbol) Is Nothing))) Then
                    Exit Do
                End If
                num = (num Or &H20)
                currencySymbol = Nothing
                ansiCurrencySymbol = Nothing
                p = (chPtr2 - 1)
            End If
        End If
        ch = ++p
    Loop
    Dim num2 As Integer = 0
    Dim index As Integer = 0
    Do While True
        If (((ch >= "0"c) AndAlso (ch <= "9"c)) OrElse (((options And NumberStyles.AllowHexSpecifier) <> NumberStyles.None) AndAlso (((ch >= "a"c) AndAlso (ch <= "f"c)) OrElse ((ch >= "A"c) AndAlso (ch <= "F"c))))) Then
            num = (num Or 4)
            If ((ch <> "0"c) OrElse ((num And 8) <> 0)) Then
                If (num2 < 50) Then
                    number.digits(num2++) = ch
                    If ((ch <> "0"c) OrElse parseDecimal) Then
                        index = num2
                    End If
                End If
                If ((num And &H10) = 0) Then
                    number.scale += 1
                End If
                num = (num Or 8)
            ElseIf ((num And &H10) <> 0) Then
                number.scale -= 1
            End If
        ElseIf ((((options And NumberStyles.AllowDecimalPoint) <> NumberStyles.None) AndAlso ((num And &H10) = 0)) AndAlso ((Not chPtr2 = Number.MatchChars(p, currencyDecimalSeparator) Is Nothing) OrElse ((flag AndAlso ((num And &H20) = 0)) AndAlso (Not chPtr2 = Number.MatchChars(p, numberDecimalSeparator) Is Nothing)))) Then
            num = (num Or &H10)
            p = (chPtr2 - 1)
        Else
            If (((((options And NumberStyles.AllowThousands) = NumberStyles.None) OrElse ((num And 4) = 0)) OrElse ((num And &H10) <> 0)) OrElse ((chPtr2 = Number.MatchChars(p, currencyGroupSeparator) Is Nothing) AndAlso ((Not flag OrElse ((num And &H20) <> 0)) OrElse (chPtr2 = Number.MatchChars(p, numberGroupSeparator) Is Nothing)))) Then
                Exit Do
            End If
            p = (chPtr2 - 1)
        End If
        ch = ++p
    Loop
    Dim flag3 As Boolean = False
    number.precision = index
    number.digits(index) = ChrW(0)
    If ((num And 4) <> 0) Then
        If (((ch = "E"c) OrElse (ch = "e"c)) AndAlso ((options And NumberStyles.AllowExponent) <> NumberStyles.None)) Then
            Dim chPtr3 As Char* = p
            ch = ++p
            chPtr2 = Number.MatchChars(p, numfmt.positiveSign)
            If (Not chPtr2 Is Nothing) Then
                ch = p = chPtr2
            Else
                chPtr2 = Number.MatchChars(p, numfmt.negativeSign)
                If (Not chPtr2 Is Nothing) Then
                    ch = p = chPtr2
                    flag3 = True
                End If
            End If
            If ((ch >= "0"c) AndAlso (ch <= "9"c)) Then
                Dim num4 As Integer = 0
                Do
                    num4 = ((num4 * 10) + (ch - "0"c))
                    ch = ++p
                    If (num4 > &H3E8) Then
                        num4 = &H270F
                        Do While ((ch >= "0"c) AndAlso (ch <= "9"c))
                            ch = ++p
                        Loop
                    End If
                Loop While ((ch >= "0"c) AndAlso (ch <= "9"c))
                If flag3 Then
                    num4 = -num4
                End If
                number.scale = (number.scale + num4)
            Else
                p = chPtr3
                ch = p(0)
            End If
        End If
        Do While True
            If (Not Number.IsWhite(ch) OrElse ((options And NumberStyles.AllowTrailingWhite) = NumberStyles.None)) Then
                If (flag2 = (((options And NumberStyles.AllowTrailingSign) <> NumberStyles.None) AndAlso ((num And 1) = 0)) AndAlso (Not chPtr2 = Number.MatchChars(p, numfmt.positiveSign) Is Nothing)) Then
                    num = (num Or 1)
                    p = (chPtr2 - 1)
                ElseIf (flag2 AndAlso (Not chPtr2 = Number.MatchChars(p, numfmt.negativeSign) Is Nothing)) Then
                    num = (num Or 1)
                    number.sign = True
                    p = (chPtr2 - 1)
                ElseIf ((ch = ")"c) AndAlso ((num And 2) <> 0)) Then
                    num = (num And -3)
                Else
                    If (((currencySymbol Is Nothing) OrElse (chPtr2 = Number.MatchChars(p, currencySymbol) Is Nothing)) AndAlso ((ansiCurrencySymbol Is Nothing) OrElse (chPtr2 = Number.MatchChars(p, ansiCurrencySymbol) Is Nothing))) Then
                        Exit Do
                    End If
                    currencySymbol = Nothing
                    ansiCurrencySymbol = Nothing
                    p = (chPtr2 - 1)
                End If
            End If
            ch = ++p
        Loop
        If ((num And 2) = 0) Then
            If ((num And 8) = 0) Then
                If Not parseDecimal Then
                    number.scale = 0
                End If
                If ((num And &H10) = 0) Then
                    number.sign = False
                End If
            End If
            str = p
            Return True
        End If
    End If
    str = p
    Return False
End Function


Вооот... Так что выбор очивиден :mrgreen:

З.Ы. Double.Parse в итоге также ссылается на ParseNumber, правда после выполнения 10 промежуточных функций, основной смысл которых в создании исключений
Изображение
You can change your face, but can`t change your mind. No matter what you do.
Создайте еще более понятный интерфейс и мир создаст еще более тупого юзера. (с) Баш

RayShade
Scarmarked
Scarmarked
Аватара пользователя
 
Сообщения: 5511
Зарегистрирован: 02.12.2002 (Пн) 17:11
Откуда: Russia, Saint-Petersburg

Re: xyz => x+y+z

Сообщение RayShade » 25.02.2009 (Ср) 11:20

Меньше знаешь, крепче спишь :)
I don't understand. Sorry.

Ramzes
Скромный человек
Скромный человек
Аватара пользователя
 
Сообщения: 5004
Зарегистрирован: 12.04.2003 (Сб) 11:59
Откуда: Из гробницы :)

Re: xyz => x+y+z

Сообщение Ramzes » 25.02.2009 (Ср) 12:57

RayShade писал(а):Меньше знаешь, крепче спишь :)

к программистам это не относится :)


Вернуться в Visual Basic .NET

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 87

    TopList  
cron